← 🏠 | ← README.md |
---|---|
→ How to... | → FAQ |
- Kute aims to be a better alternative to other libraries
- How is Kute better than others for implementing
toString()
?
- Java's built-in
Objects.toString()
- Apache's
ToStringBuilder
(and other, comparable solutions) - Lombok's
@ToString
annotation- Lombok's
@ToString
is really good if you get it working - But it does not work with later versions of IntelliJ, with maddening version dependencies between IntelliJ, Maven / Gradle plugins, IntelliJ plugin,
javac
, and Lombok (maybe some bugs too?).
Lombok and Kotlin are not always friends either.
- Lombok's
Gson
andJackson
- May work well for you if
json
is OK for you. - But these are intended in first place for serialization, not for
String
representation in logging, etc.Gson
andJackson
do not take precautions to prevent them (e.g.StackOverflowException
with recursive data). And they shouldn't, of course!Gson
andJackson
keeptransient
properties out of their output, which is correct for serialization, but may not be intended fortoString()
- May work well for you if
- IDE generated
toString()
methods- IDE generated
toString()
methods are simple and light-weight, but not maintenance-friendly (refactoring)
- IDE generated
- Ease of use
- With Kute, a
toString()
method typically is as simple as
override fun toString(): String = asString()
- With
Objects.toString()
, you have to call it for every individual property - ugly codepublic override toString() = Objects.toString()
does not work!
(throwsStackOverflowError
!!)
- With
String
representation of any Java or Kotlin object is as simple asobj.asString())
- No maddening issues with plugins and version dependencies
- With Lombok, getting it working may be maddening, due to combination of Lombok, IntelliJ, Kotlin, Gradle / Maven plugins, javac and IntelliJ settings and versions that may or may not work together.
- You probably need to downgrade IntelliJ to some 2019(!) version to make it work 😭...
- Switching from Gradle to Maven may help too 🤯...
- With Lombok, getting it working may be maddening, due to combination of Lombok, IntelliJ, Kotlin, Gradle / Maven plugins, javac and IntelliJ settings and versions that may or may not work together.
- No fear for exceptions
toString()
implementations should never get in your way.- With Kute, you never have to include a
try
...catch
-block in yourtoString()
- With most (all?) alternatives, you do have to care for exceptions in your
toString()
methodAnd maybe you'll realize so at an inconvenient time in the night or weekend...
- Apache's
ToStringBuilder
orObjects.toString()
,Gson
orJackson
do propagate exceptions
- With most (all?) alternatives, you do have to care for exceptions in your
- With Kute, in many cases, exceptions are prevented rather than caught
- If exceptions are encountered yet, they are handled gracefully and not propagated to the caller
- If exceptions are encountered yet, they are handled gracefully and not propagated to the caller
- With Kute, you never have to include a
- Embraces
null
- Kute renders
null
s by default, and is fullynull
-safe- With Kotlin: fully
null
-safe; with Java:null
-safe in nearly all situations.
- With Kotlin: fully
null.asString()
returns"null"
; same goes for properties withnull
value.- Apache's
ToStringBuilder
is not null-safe - With
Gson
, you need to use a builder to havenull
s serializedGsonBuilder().serializeNulls().create().toJson(obj)
- Kute renders
- Kute is intended primarily for
String
representations for use in logging, etc.Gson
andJackson
are intended for serialization
- Any object, including Lambda's,
Number
, collections, maps, custom objects, native Java & Kotin stuff, synthetic objects, can be represented asString
by callingobj.asString()
- With Kute, a
2. Stability
Objects.toString()
and Apache'sToStringBuilder
are less stable than you might hope or expect...
- As a developer, I don't want any
toString()
-like thing get in the way- I want decent output and no
NullPointerException
when the object I called it on appears to benull
Apache's
ToStringBuilder
is notnull
-safe
→ you need something likeobj?.let { ToStringBuilder.reflectionToString(it) }
on nullable objects (in Java even more ugly) - I really don't want to care about any exception (neither
RuntimeException
norException
) in mytoString()
methods 😑 - With Kute you get decent output (and no
ConcurrentModificationException
) when aCollection
orMap
is modified concurrently by another thread- Note that, due to reflective access, this
ConcurrentModificationException
may occur even when theCollection
orMap
is properly guarded (e.g.private
orprotected
) - Both
Objects.toString()
and Apache'sToStringBuilder
let exceptions go unhandled - Kute takes an optimistic approach, by not preventively taking a defensive copy of collections etc.
- When
ConcurrentModification
occurs, it is caught and a defensive copy is taken. If aConcurrentModification
(or other exception) occurs again while taking the defensive copy, Kute falls back to a default representation that omits the collection's content.
- When
- Note that, due to reflective access, this
- You can exclude properties (e.g.
Collection
s of child records in database-stuff like entities in JPA, Hibernate, Exposed, etc.), to avoid performance issues by reflective collection of data- Apache's
ToStringBuilder.reflectionToString
has this option as well (@ToStringExclude
) Gson
has a more complicated approach to excluding properties
- Apache's
- Kute's
asString()
outputs recursive data properly, withoutStackOverflowError
- Lombok's
ToString
also handles recursive data properly! 👍🏽👍🏽 Objects.toString()
, Apache'sToStringBuilder
andGson
let your application crash withStackOverflowError
on recursive data 👎🏽 (assuming you don't catchError
stuff)- Recursive data are quite common, actually, and should not blow up your
toString()
anyway. For example, think of:- Circular routes in route or flight planning
- Parent-child relationships in data-centric applications, where the child refers to the parent, and the parent has a list of children
- Nested collections, where the same object may appear in both the outer and inner Lists
- Custom linked-list implementations, where each element points to its predecessor, and/or its successor
- ...
Even while you might hate such constructs, you may have to deal with them, and you probably want them represented without
StackOverflowError
, I assume...
- Lombok's
- I want decent output and no
3. Better
String
representation
- You hate things like
[Ljava.lang.Object;@e3b3b2f
as much as anybody- You expect that Lambdas are represented decently
- You hate it when every object is preceded by its fully qualified package name
- You hate yourself and your IDE when you forgot to include the newly added property in your IDE-generated
toString()
implementation (and even more when it's causing issues in production)
- Why better:
- Dynamic (reflective) property representation of custom Java and Kotlin classes
- Never forget adding new properties / correcting renamed properties
- Built-in protection against
StackOverflowError
in case of self-references, or mutual/circular references - Adheres by default to implicit
toString()
representation of Kotlin data classes - Adheres by default to
Array.contentDeepToString()
, and totoString()
representation ofCollection
andMap
- But with protection against recursive data !
- Adheres to Java- and Kotlin
toString()
for built-in stuff- E.g. for
Date
,DateTime
,Number
,CharSequence
,String
,UUID
, etc.
- E.g. for
- Improved handling for Lambdas and functional interfaces to give a much better representation
than default
toString()
, IDE-generatedtoString(),
Apache'sToStringBuilder
orObjects.toString()
- 👉🏽 If your custom objects feature carefully implemented
toString()
implementations, you can have these preferred by applying@AsStringClassOption(toStringPreference = PREFER_TOSTRING)
Or, alternatively, by applying
ToStringPreference.PREFER_TOSTRING
as application-wide default
- Dynamic (reflective) property representation of custom Java and Kotlin classes
4. Kotlin first
- By default, Kute's
asString()
representation of objects is equal to Kotlin'stoString()
representation of data classes- To be used with any object (including Lambda's,
Number
, collections, maps, custom objects, native Java & Kotlin stuff, synthetic objects,null
, ...)
- To be used with any object (including Lambda's,
- Kute offers the option to include
companion
objects in theasString
output - Kute handles
lateinit
properties decently, whether initialized or not - Intuitive API by usage of extension methods:
asString()
can be called on any object (evennull.asString()
).
5. Protection of Personally Identifiable Data / GDPR
Think of properties that contain data like family names, dates of birth, bank account numbers, ID-card numbers, e-mail addresses, social media account names, login names, password data (no plain text, hopefully!), etc. etc. etc.
- Kute has several options that may help to keep Personally Identifiable Data out of your log files:
- Property values can be masked (fully or partially) with
@AsStringMask
- Property values can be represented by their hashed value with
@AsStringHash
- Property values can be replaced (fully or partially) with
@AsStringReplace
- using regular expressions, or by plain text
- Properties can be excluded completely with annotation
@AsStringOmit
- Property values can be masked (fully or partially) with