You are especially encouraged to check out the How to... page → It gives an overview of all options of Kute asString() , with further links:e.g. on how to start with Kute asString() , examples / snippets, etc.) |
---|
Kute stands for Kotlin Utility.
And also for cute, as it was intended to be a tiny, little, cuddly, easy to use utility.
Currently, Kute contains asString()
, which is basically a toString()
alternative,
but customizable to fit your needs.
And with many practice-based, developer-friendly features.
Comparable with Apache's
ToStringBuilder.reflectionToString
- but better!
Stay with me: see Basic ideas of Kute's asString() and How is Kute better?
More advanced options are available, but basically it should be very easy to use,
never getting in the way when developing great code (or when troubleshooting less great code).
Kute is built with the following ideas about toString()
implementations in mind:
- Untroubled
toString()
implementations should be as basic as possible.- Renaming, adding or removing properties should be followed automagically
You really should not have to bother about your
toString()
implementations.
So you can focus on the functionals you are working on. - Helpful
toString()
's purpose is to help solving issues, not to cause new issues- Exceptions should never propagate out of your
toString()
. Period.- Uhmmm... except
InterruptedException
andCancellationException
- Uhmmm... except
- If your object model includes recursive data, you still want your
toString()
giving you the information you expect
(withoutStackOverflowError
) - If your data is modified concurrently, you still don't want to have a
ConcurrentModificationException
thrown by yourtoString()
method
- Decent & informative
- Decent, informative, human-readable representation of just any object, whether your own custom-made stuff,
library objects, or Java/Kotlin built-in stuff
- Decent, informative, human-readable representation of just any object, whether your own custom-made stuff,
- Customizable
- In practice, there will be some obstacles that you need to tackle, and where you want customization:
- GDPR / Personally Identifiable Data
- You may want to keep certain data out of log files (omitted completely, or hashed, or ...)
- Data that you want to exclude, to prevent performance issues
- E.g. output of a
List
of children in JPA Entities may not be desirable (think of performance, verbosity)
- E.g. output of a
- Customization to your personal or business preferences
- GDPR / Personally Identifiable Data
- In practice, there will be some obstacles that you need to tackle, and where you want customization:
- Zero transitive dependencies
- See below, under Compatibility → dependencies
- IDE generated
toString()
methods - Apache's
ToStringBuilder
(and other, comparable solutions) - Java's built-in
Objects.toString()
- Lombok's
@ToString
annotation- Lombok's
@ToString
is really good; but it has maddening dependencies between IntelliJ, Gradle, IntelliJ plugin,javac
, Kotlin, and Lombok.
Chances are well that you can't get it working in your environment.
- Lombok's
Gson
andJackson
json
-libraries 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.- Think of lengthy
Collection
s - you can't limit the amount of String data with these libs - they shouldn't!
- Think of lengthy
- Home-grown solutions
Below, a summary of why Kute is a better choice for your toString()
implementations.
Want more details? See → How is Kute better than others on how Kute compares to:
Apache'sToStringBuilder
,Objects.toString()
, Lombok's@ToString
,Gson
-
Ease of use
- With Kute, a
toString()
method typically is as simple as
override fun toString(): String = asString()
- No maddening issues with plugins and version dependencies (like with Lombok)
- Fully
null
-safe & no fear for exceptions
- With Kute, a
-
Stability
- As a developer, I don't want any
toString()
-like thing get in the way - I really don't want to care about any exception in my
toString()
implementations:NullPointerException
,RuntimeException
,ConcurrentModificationException
, ...
- I do want my
toString()
handle recursive data properly, withoutStackOverflowError
- I want the option to limit or exclude properties, e.g.
Collection
s of child records in database-stuff
(JPA, Hibernate, Exposed, etc.), to avoid performance issues by reflective collection of data.- Use
@AsStringOmit
for individual properties - Use property filters for categories of properties
- Use
- Kute has been tested against various JVM's / Java versions / Kotlin versions / OS
- Kute is tested heavily with all kinds of exotic objects and properties
- Think of delegates,
lateinit
, property extensions, properties with explicitget
-ters, object expressions,
nested classes, anonymous classes, companion objects, recursive / mutually referencing data, synthetic stuff,
SAM-wrappers, callables, fun interfaces, etc. etc. etc.- Apache's
ToStringBuilder
andObjects.toString()
fail on some / several of these. Gson
andJackson
fail on recursive data.
They should: they are not intended fortoString()
-like usage, but for serialization.
- Apache's
- Think of delegates,
- As a developer, I don't want any
-
Better
String
representation- You hate things like
[Ljava.lang.Object;@e3b3b2f
as much as anybody - You hate yourself and your IDE when you forgot to include the newly added property in your IDE-generated
toString()
implementation
(even more when it's causing issues in production)
- Built for
String
representations, to use in logging, etc. - Improved representation of Lambdas and functional interfaces
Array
representation likecontentDeepToString
- Automatic resolution of custom objects
- Options to have properties sorted by type, name, value length, etc.
- Especially useful for entities with (too) many properties
- 👉🏽 If your custom objects feature carefully implemented
toString()
implementations, you can have these preferred- E.g. by using
@AsStringClassOption(toStringPreference = PREFER_TOSTRING)
- E.g. by using
- You hate things like
-
Kotlin first
- By default, Kute's
asString()
representation of objects is equivalent to Kotlin'stoString()
representation
of collections, Kotlin'sdata
classes, etc. - Proper handling of
lateinit
properties - Option to include
companion
objects in theasString
output - Intuitive API by usage of extension methods etc.
- By default, Kute's
-
Protection of Personally Identifiable Data / GDPR
- Kute has several options that may help to keep Personally Identifiable Data out of your log files
(or, in general, out of yourtoString()
representations)
- Kute has several options that may help to keep Personally Identifiable Data out of your log files
-
Performance
- You want
toString()
methods with performance comparable to IDE-generatedtoString()
methods - You want the possibility to exclude individual properties or certain categories of properties
- E.g., if your JPA entities contain lists of child entities, you want to keep the child entities
out of the parent's String representation
You don't want your
toString()
have fetching records from the database...!
- E.g., if your JPA entities contain lists of child entities, you want to keep the child entities
out of the parent's String representation
- You want
- Kute is built for compatibility with Java 11+
- Kute has been built and tested on various JVMs with Java versions 11 to 20.
- Kute has been built and tested on different environments, e.g. MacOs and Windows
- Building API documentation on Windows has known issues.
- Contributors: see comments in Gradle task buildWithApiDocs
- Building API documentation on Windows has known issues.
- Contributors are asked to have Kute tested on a Java 11 JVM
- Not just with
sourceCompatibility
/targetCompatibility
11, but really have it built and tested on a Java 11 JVM. - For instance,
HexFormat
class can not be used (added in Java 17) - The
Gradle
build script build.gradle.kts outputs the Java version by means of
println("Running on JVM version: ${JavaVersion.current()}")
- Not just with
- Current Kotlin version for Kute is
1.9.x
- But the Kotlin version should not have runtime implications
- All versions of Kotlin produce Java 8+ compatible code
- Also tested with Kotlin
1.3
without issues- I.e., no issues at the time of writing
- But: no effort or even guarantees that 1.3 compatibility will be maintained for Kute
asString()
- But the Kotlin version should not have runtime implications
- Kute is built with zero-dependencies as a basic principle.
Applications that use Kute shall not face any additional transitive dependency through Kute. Hence:- Kute's runtime code should not rely on any 3rd-party library
- Just on Java and Kotlin built-ins,
kotlin-stdlib
,kotlin-reflect
- Just on Java and Kotlin built-ins,
- No logging framework is included or presumed
- Tests & build scripts use 3rd-party libraries, though
- These do not induce runtime dependencies
- Tests of Kute may use any library they wish, like
JUnit
,Mockito
,AssertJ
,Awaitility
, Apache's Common Lang,Gson
, etc. - Gradle build scripts may use any library / plugin they wish, e.g.
Dokka
,pitest
,kover
, Apache'scommons-io
, etc.
- Kute's runtime code should not rely on any 3rd-party library
- Kute is built with the
JVM
platform in mind.- It uses Kotlin's reflection wherever possible
- But various edge cases are not supported by Kotlin's reflection.
In these cases, Java's reflection is used.
- Tests are also made with the
JVM
platform in mind- Using
JUnit 5
,Mockito
,AssertJ
,Awaitility
, etc.
- Using
Porting Kute to another platform won't be easy.
It uses Kotlin's reflection wherever possible.
But, some edge cases are not supported by Kotlin's reflection. In these cases Java's reflection is used.
Besides that, the JVM-platform is omnipresent in Kute; so porting it would probably result in a need to rewrite quite some code,
maybe with limited functionality (due to limitations of Kotlin's reflection).
In my opinion (being the author, Jan-Hendrik van Heusden) Kute asString
should be a mature, practice-oriented library.
The current version is heavily tested with more exotic stuff than you probably ever will have in your code-base.
Still, we all know that practice may have more tricks than you can imagine!
NB: not tested with a restrictive SecurityManager.
I have a few things I'd like to improve yet. And maybe others may contribute!
-
Tests with a restrictive SecurityManager? But maybe Kute
asString()
isn't the best solution for that anyway;
in such environments you may rather want to stick with IDE-generatedtoString()
implementations. -
Logging: Kute only logs exceptional situations, so quite minimal.
However, Kotlin's reflection does not like some situations (e.g. Java classes with anonymous inner classes,
classes nested inside methods, etc.), and throws a reflection-exception.
This situation is handled gracefully, but not logged, to avoid clogging your log files or std-out.
The output is different from normal, though, so it may leave the user with questions why she does not get the expected output.
A choice for more verbose logging should be implemented, to service situations like these. -
Option to have all provided
NameValue
implementations honour annotations.
Currently this is only the case forNamedProp
.
I'd like to hear more about your experiences with Kute asString()
, and any wishes.
- Feel free to suggest changes by adding a pull request.
- See how to contribute!
- Or discuss what / how you want to have things improved or extended.
Kute is an open-source project, according to The Open Source Definition of the Open Source Initiative®, under MIT-license.
The license statement can be found in the project root: see the → LICENSE.