I have an idea to introduce new annotation: @ToJson. It should work similarly to @ToString, but the output will be JSON format.
Use cases:
@gdmn, :+1: Jackson ObjectMapper?
Or GSon or XXX. How to configure the object mapper (property format, conversion, etc.), can I inject an existing object mapper instance.
This does not look like something I'd want for lombok. This somehow breaks the _separation of concerns_ design principle.
And you can already go for Jsonb.create().toJson(object) on java ee 8.
No matter what would be the implementation, this would be a bad idea because a lot of configuration can be done and then you would ask to add them in the new annotation.
Another reason for this could be performance. Compile time generation of a toJson() method would lead to much faster serialization than using any Json serialization libraries.
Agree that by we open a door for too many customization requests, but the same can also be said of ToString.
Thoughts?
The difference between toStringand a toJson method is that you already have a method signature you have to follow for toString.
What is a JSON in Java ? The Jackson JsonNode ? A String ?
What if your application is a J2SE project and you don't have any of the Jackson, GSon, JsonP or JsonB library ?
While the @ToString annotation is a developper quality of life improvement and shall not have an impact on production code, a @ToJson annotation would never fit all production cases for JSON conversion.
JSON would be a Json String, to give clarity we can keep the annotation as @ToJsonString.
I think that's a low level problem, and there would be a very small percentage of people who would not assume that @ToJson would produce a Json String.
I agree with your concerns for a choice of library, and but that can always be pointed in fine-print. Also if you are saying we are being impartial to a libary, I think that ship sailed a long time ago ,when lombok added support for Jackson annotations.
Even @ToString does not fit all production use cases, for eg: the other day I wanted toString() to vend out with : instead of =, but that is OK, I chose to write my implementation of it, rather than use @ToString, which is what anyone, who doesn't like the standard implementation of ToJson would do.
I think @ToJson, does solve a fairly common occurring problem of representing a Java POJO as a Json String.
A major concern I have though is about the feasibility of implementing this, perhaps @Maaartinus or @rzwitserloot can shed some light on that.
@mehwhatever
Also if you are saying we are being impartial to a libary, I think that ship sailed a long time ago ,when lombok added support for Jackson annotations.
I don't think so. Lombok can support annotations from ten JSON libraries at the same time as AFAIK all it does is to recognize and copy Jackson annotations when appropriate.
A major concern I have though is about the feasibility of implementing this, perhaps @Maaartinus or @rzwitserloot can shed some light on that.
I guess, the big difference is that @ToString can rely on toString() existing in every class. The worst thing what can happen is inheriting it from Object, which is pretty always useless, but it compiles and sort of works.
With @ToJson it's worse. Lombok can't find out whether there's a toJson() method for the field Whatever whatever;, so what can it do? Simply calling into some library for every field would do, but then, what do you need Lombok for?
I guess, the big difference is that
@ToStringcan rely ontoString()existing in every class. The worst thing what can happen is inheriting it from Object, which is pretty always useless, but it compiles and sort of works.With
@ToJsonit's worse. Lombok can't find out whether there's atoJson()method for the fieldWhatever whatever;, so what can it do? Simply calling into some library for every field would do, but then, what do you need Lombok for?
What if, instead, the supposed @ToJson method would simply create a @ToString that produces a JSON string?
@marcoXbresciani That makes a lot of sense.
@Maaartinus , do you see any issues with this? @ToJson or @ToString(json=true) will just return a Valid JSON. For complex objects, I think it would just call toString, and it is the onus to the user to ensure @ToString(json=true), if he wants the inner object, is enabled through the hierarchy.
Although I may be late to the party, I don't see any further issues besides
toString().The only argument here against using a dedicated library like Jackson is performance. However, Jackson is really fast even though it uses reflection (reflection isn't a real perfomance issue in recent Java versions any more, if it's done right). If you really want a compile-time solution, there is dsl-json, which offers compile-time code generation via annotation processor.
The killer is that 'toString, but.. JSON' just doesn't do anything useful: Let's say you have a class named Person and inside is a field of type Address. When we generate a toString() we just call toString() on the value for the address field and assume that's sensible.
But that'd obviously be a very daft idea for the toJson method. The obvious solution is to call the toJson() method of whatever this Address thing is but how do we KNOW that this method exists? At least with toString we know it is there.
Further issues:
Lombok needs a sizable 'library' of how to jsonify commonly used types. Lombok just needs to be able to jsonify for example LocalDate (presumably, render as a string with yyyy-MM-dd), Instant (oh dear, that is a lot trickier. Do we try a longer dateformat including hours and millis and such, or, do we do epoch-millis?), as well as all maps, strings, and lists – all stuff @ToString does NOT care about (the default toString of List itself is fine and is why things work out). That's a LOT of effort, and all stuff we need to maintain. I assume there'll be lots of feature requests to add more jsonifiers to the library all the time.
It should really be named toJson; the style guides all agree that you should not copy all-caps in acronyms appearing in java identifiers. And yet just about every json library out there seems to use toJSON. Do we follow the crowd off the cliff or break with tradition?
_IF_ we even go down the rabbithole of allowing resolution to figure out what types actually are and if they have a toJson method we could call, do we structurally type? Do we just have a list of method names which we'll assume do the right thing (toJSON, toJson, asJson, etc?)... or do we introduce an interface? That's not useful for lots and lots of code out there. We can forego resolution and just hardcode that we call toJson on any field of unknown types and rely on the compiler to error on that call if that method isn't there, but.. lots of stuff out there has a method named toJSON instead. How do we tackle this problem?
jsonifying strings is not actually all that easy; the escaping code is quite a few .replace calls. Lombok intentionally does not use a runtime library, so either we change the rules and now demand that lombok.jar is present at runtime, or we inject the full code in _every_ class, or we require that some known library with a simple 'jsonify this string' method is present and we generate a call to this.
In other words, I see whole heaps of trouble, and any passing off of this idea as 'its about as complicated as ToString' will therefore be justifiable laughed away.
Given the complications, this is well beyond my tolerance levels to build it.
Furthermore, a pull request with the full feature is tricky; there is a high maintenance burden here, and I assume nobody is quite willing to staple a signed contract stipulating free continued support of the feature for a few years to your pull request, so, we'd be signing up for that job.
Still, it WOULD be kinda cool. If someone really wants to go for it, talk to us. Maybe we can come to an agreement. I think if the PR truly covers ALLLL the bases (so not just all of the above, but also tests and documentation) we'd take on the maintenance burden.
The one remaining problem is that I don't see how you can 'detect' jsonable types without resolution, and piling a resolution requirement on top of this feature truly ruins it. So, presumably then we'd be back to: Well, we just call toJson and if that method isn't there, a compiler error would ensue. So, we'd need a detailed analysis of how often some sort of toJson method is already part of commonly used types in value classes (think ImmutableList, for example), and what they are named.
Given how complex this is, I'm going to close this issue. We'll re-open if someone contacts us to take on the work.
Most helpful comment
Or GSon or XXX. How to configure the object mapper (property format, conversion, etc.), can I inject an existing object mapper instance.
This does not look like something I'd want for lombok. This somehow breaks the _separation of concerns_ design principle.