Jackson serialization: how to ignore superclass properties - java

I want to serialize a POJO class which is not under my control, but want to avoid serializing any of the properties which are coming from the superclass, and not from the final class. Example:
public class MyGeneratedRecord extends org.jooq.impl.UpdatableRecordImpl<...>,
example.generated.tables.interfaces.IMyGenerated {
public void setField1(...);
public Integer getField1();
public void setField2(...);
public Integer getField2();
...
}
You can guess from the example that that this class is generated by JOOQ, and inherits from a complex base class UpdatableRecordImpl which also has some bean property-like methods, which cause problems during the serialization. Also, I have several similar classes, so it would be good to avoid duplicating the same solution for all of my generated POJOs.
I have found the following possible solutions so far:
ignore the specific fields coming from superclass using mixin technique like this: How can I tell jackson to ignore a property for which I don't have control over the source code?
The problem with this is that if the base class changes (e.g., a new getAnything() method appears in it), it can break my implementation.
implement a custom serializer and handle the issue there. This seems a bit overkill to me.
as incidentally I have an interface which describes exactly the properties I want to serialize, maybe I can mixin a #JsonSerialize(as=IMyGenerated.class) annotation...? Can I use this for my purpose?
But, from pure design point of view, the best would be to be able to tell jackson that I want to serialize only the final class' properties, and ignore all the inherited ones. Is there a way to do that?
Thanks in advance.

You can register a custom Jackson annotation intropector which would ignore all the properties that come from the certain super type. Here is an example:
public class JacksonIgnoreInherited {
public static class Base {
public final String field1;
public Base(final String field1) {
this.field1 = field1;
}
}
public static class Bean extends Base {
public final String field2;
public Bean(final String field1, final String field2) {
super(field1);
this.field2 = field2;
}
}
private static class IgnoreInheritedIntrospector extends JacksonAnnotationIntrospector {
#Override
public boolean hasIgnoreMarker(final AnnotatedMember m) {
return m.getDeclaringClass() == Base.class || super.hasIgnoreMarker(m);
}
}
public static void main(String[] args) throws JsonProcessingException {
final ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector(new IgnoreInheritedIntrospector());
final Bean bean = new Bean("a", "b");
System.out.println(mapper
.writerWithDefaultPrettyPrinter()
.writeValueAsString(bean));
}
}
Output:
{
"field2" : "b"
}

You can override the superclass' methods which you'd like to prevent from being output and annotate them with #JsonIgnore. The override shifts the control of property creation to the subclass while enabling its ability to filter it from the output.
For instance:
public class SomeClass {
public void setField1(...);
public Integer getField1();
public void setField2(...);
public Integer getField2();
#Override
#JsonIgnore
public String superClassField1(...){
return super.superClassField1();
};
#Override
#JsonIgnore
public String superClassField2(...){
return super.superClassField2();
};
...
}

You can use this as well instead of unnecessary overrides
#JsonIgnoreProperties({ "aFieldFromSuperClass"})
public class Child extends Base {
private String id;
private String name;
private String category;
}

The good use of inheritance is that the child classes extend or add functionality. So the usual way is to serialize the data.
A workarround would be to use a Value Object (VO) or Data Transfer Object (DTO) with the fields you need to serialize. Steps:
Create a VO class with the fields that should be serialized.
Use BeanUtils.copyProperties(target VO, source data) to copy the properties
Serialize the VO instance.

Add the following annotation in your Base Class :
#JsonInclude(Include.NON_NULL)

Related

Passing anonymous type to annotation

I want to pass an anonymous type to an annotation. As I dont know how to explain my problem in words properly, I'll just explain my intention and my code.
I'm currently writing a serializer/deserializer for Java to JSON. Every class then needs to implement a specific interface to be serializable and every field also needs an annotation, so my serializer knows which fields to serialize.
#Retention(RetentionPolicy.RUNTIME)
#Target(FIELD)
public #interface SerializeField {
Class<? extends Formatter> formatter();
}
Now i added the ability to specify a formatter that generates a string for a field.
public interface Formatter<T> {
public abstract String format(T object);
}
This works fine when I just create a new class that implements Formatter but does not work when I create an anonymous class or use a lambda expression.
public class Test implements Javonable {
//This does not work
Formatter<BigDecimal> bigDecimalFormatter = (BigDecimal object) -> object.toString();
#SerializeField(formatter = bigDecimalFormatter.getClass())
private BigDecimal bigDecimal; // ^ The value for annotation attribute SerializeField.formatter must be a class literal
//This does work
#SerializeField(formatter = BigIntegerFormatter.class)
private BigInteger bigInteger;
public class BigIntegerFormatter implements Formatter<BigInteger> {
#Override
public String format(BigInteger object) {
return object.toString();
}
}
}
Is there something that I don't see or is there a solution for that? In the end I just want to be able to pass a Formatter as simple as possible without having to create a new class each time.

Rename field only on Serialization in java

I have an object named AddOnsSRO.Only on serialization I want the names of fields of the object to be changed.
Tried using #JsonProperty on getter methods but it gives me a renamed field even on usages where serialization is not involved.
public class AddOnsSRO {
private String sideCar;
private String sideCarCoverage;
#JsonSerialize
#JsonProperty("abc")
public String getSideCar() {
return sideCar;
}
public void setSideCar(String sideCar) {
this.sideCar = sideCar;
}
#JsonSerialize
#JsonProperty("xyz")
public String getSideCarCoverage() {
return sideCarCoverage;
}
public void setSideCarCoverage(String sideCarCoverage) {
this.sideCarCoverage = sideCarCoverage;
}
}
Only on serialization the following fields : sideCar and sideCarCoverage must be renamed to abc and xyz respectively.
For any other use except serialization the field names should be sideCar and sideCarCoverage only.
Please help and suggest changes or annotations accordingly.
For effecting only serializing use #JsonGetter instead of #JsonProperty
#JsonGetter("abc")
public String getSideCar() {
return sideCar;
}
Getter means that when serializing Object instance of class that has this method (possibly inherited from a super class), a call is made through the method, and return value will be serialized as value of the property.
You can add #JsonSetter to setter method for deserialize:
#JsonSetter("sideCar")
public void setSideCar(String sideCar) {
this.sideCar = sideCar;
}
your code looks good...Please upgrade your jackson lib... if you are using old

Programmatically accessing #JsonProperty from Java

I have the following POJO using Immutables+Jackson under the hood:
#JsonInclude(JsonInclude.Include.NON_NULL)
abstract class AbstractQueryRequest {
#JsonProperty("reqid")
public abstract String reqid();
#JsonProperty("rawquery")
public abstract String rawquery();
}
At some point I need to build another object based on the fields of the POJO, something along this line:
final HttpUrl.Builder urlBuilder = HttpUrl.parse(cfg.baseUrl()).newBuilder();
urlBuilder.addQueryParameter("reqid", request.reqid())
.addQueryParameter("rawquery", request.rawquery());
It's quite annoying to keep the POJO and this call aligned upon changes, I was wondering if it was possible to access programmatically each JsonProperty instead of typing the string manually.
Note that it is fine to write the getters by hand as I can easily refactor and I have the compiler double checking, but for strings I am worried for people down the line and I would like to "read" them from the POJO class somehow.
You can do it via reflection. You need to take method annotation values which annotated with JsonProperty. But I recommend you to use JsonProperty on fields, not methods.
Here is an example for your current requirement :
public class Main {
public static void main(String[] args) {
AbstractQueryRequest someType = new SomeType();
for(Method method : x.getClass().getSuperclass().getDeclaredMethods()) {
if (method.isAnnotationPresent(JsonProperty.class)) {
JsonProperty annotation = method.getAnnotation(JsonProperty.class);
System.out.println(annotation.value());
}
}
}
}
class SomeType extends AbstractQueryRequest {
#Override
public String reqid() {
return null;
}
#Override
public String rawquery() {
return null;
}
}
Output is :
rawquery
reqid

How to add derived properties to a Jackson 2 serialized class?

I'm serializing some existing objects with Jackson 2.22, leveragin the MixIn feature to decouple the real object from the Jackson annotations configuration.
Actually my mixin is an interface that declares the same methods of the target class and annotates them, here's an example.
Target class:
public class Product {
// ...
public String getName();
public String getDescription();
public String getPrice();
public String getFinalPrice();
public String getDiscount();
// ...
}
and the mixin:
public interface ProductApi {
#JsonProperty
public String getName();
#JsonProperty("price")
public String getFinalPrice();
}
My JSON should have some more informations, computed from several methods or fields of the target class.
Is this even possible in Jackson?
I tried turning the mixin in a class and adding a new method there, but that didn't work.
public class ProductApi {
#JsonProperty
public String getName();
#JsonProperty("price")
public String getFinalPrice();
#JsonProperty("images")
public List<String> getImages() { /* ... */ }
}
I guess this is because the mixin only provides annotations for the target class, but is the latter that is read for serialization.
Of course, if I change the object to be serialized with a new subclass that contains the new method I need, that works, but the objects come from our services layers, and this would mean I have to rewrite all those methods.
I'm using Jackson with Jersey, so don't want to change Jackson with another library.
Here's how I did it.
The solution is to specify a custom JsonSerializer implementation to the field getter.
First of all, I changed the mixin interface to a class that extends the entity (target) class, so that it can access the target class data.
public class ProductApi extends Product {
#JsonProperty
#Override
public String getName() {
return super.getName();
};
// ...
}
Next, I implemented the JsonSerializer that would create the derived property I want:
public static class ImagesSerializer extends JsonSerializer<String> {
#Override
public void serialize(String value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
Product p = (Product) jgen.getCurrentValue();
int num = p.getNumberOfImages();
List<String> imgs = new ArrayList<String>(num);
for(int i = 0; i < num; i++) {
String src = "/include/images/showImage.jsp?"+"id="+p.getId()+"&number="+i;
imgs.add(src);
}
provider.defaultSerializeValue(imgs, jgen);
}
}
This is a really simple implementation, more safety checks should be done.
What this does is, basically, retrieve the whole entity instance from the JSON generator, build up a custom object and then ask Jackson to serialize it.
I implemented it inside my ProductApi as a static class, but just for simplicity.
Finally, the serializer needs to be bound to the JsonProperty annotated field:
public class ProductApi extends Product {
#JsonProperty
#Override
public String getName() {
return super.getName();
};
// ...
#JsonSerialize(using=ImagesSerializer.class)
#JsonProperty("images")
#Override
public String getImage() { // in my entity this returns an image number, whereas in my JSON I want a list of URLs
return "";
}
// ...
}
As a side note, it seems that the returned value of the getImage() method is not used.
Why don't you just make some fields, which should be serialized and use Gson for it?

Automatic generation of immutable class and matching builder class of a Java interface

What tools or libraries exists for Java that will take an interface only with accessor method definitions and automatically generate an immutable object class and also a "builder" class for incrementally building new instances or changing existing instances by creating new ones?
Example input:
public interface Car {
String getModelName();
int getWheelCount();
}
Example output:
import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.NotThreadSafe;
#Immutable
public final class ImmutableCar implements Car {
#NotThreadSafe
public static final class Builder implements Car {
private String modelName;
private int wheelCount;
public Builder() {
}
public Builder(final Car car) {
modelName = car.getModelName();
wheelCount = car.getWheelCount();
}
public ImmutableCar build() {
return new ImmutableCar(wheelCount, modelName);
}
#Override
public String getModelName() {
return modelName;
}
#Override
public int getWheelCount() {
return wheelCount;
}
public void setModelName(final String modelName) {
this.modelName = modelName;
}
public void setWheelCount(final int wheelCount) {
this.wheelCount = wheelCount;
}
}
private final String modelName;
private final int wheelCount;
public ImmutableCar(final int wheelCount, final String modelName) {
this.wheelCount = wheelCount;
this.modelName = modelName;
}
#Override
public String getModelName() {
return modelName;
}
#Override
public int getWheelCount() {
return wheelCount;
}
}
Immutables (http://immutables.github.io) annotation processor is the exact match for your needs. It is full-featured and very customizable (you know all those set vs with vs no-prefix wars, - use whatever you prefer). It can generate immutable implementation with builders for interfaces, abstract classes, annotations. In addition, it can generate builders to invoke static factory methods or POJO constructors and many other things.
#Value.Immutable
public interface ValueObject {
String name();
List<Integer> counts();
Optional<String> description();
}
// Compile using annotation processor and use it like this
ValueObject valueObject =
ImmutableValueObject.builder()
.name("My value")
.addCounts(1)
.addCounts(2)
.build();
Google have a tool called AutoValue that does this, except based on an abstract base class instead of an interface.
import com.google.auto.value.AutoValue;
class Example {
#AutoValue
abstract static class Animal {
static Builder builder() {
return new AutoValue_Example_Animal.Builder();
}
abstract String name();
abstract int numberOfLegs();
#AutoValue.Builder
abstract static class Builder {
abstract Builder name(String s);
abstract Builder numberOfLegs(int n);
abstract Animal build();
}
}
}
Another similar tool is Immutables; this is probably a closer match to the question, as it uses an interface and generates an immutable implementation and a builder.
Lombok allows code like this:
#lombok.Data
#lombok.Builder
public class ImmutableCar implements Car {
private final #lombok.NonNull String modelName;
private final #lombok.NonNull int wheelCount;
}
The lombok annotations are processed at compile time (JSR-269) to generate the full class. It is also possible to look at the generated code by 'delomboking' via a Maven plugin.
check out Eclipse Model2Text project and its subprojects, especially Acceleo and Xpand. they are generally used to generate EMF-based Java code for EMF models but they can be used to generate simple POJOs too.
however this functionality does not come out of the box: you'd have to create your own code generator and templates for it. see Accelelo tutorial .
EDIT:
one more idea - one so simple that it took me a day to realize it
you can use Velocity, Freemarker or similar template library (which are normally used for html generation). though still you need to make a model somewhere, in a .txt or .xml file for example. here's a tutorial on Velocity code generation.
I just created an eclipse plugin https://github.com/karajdaar/templator.
It generates code based on Freemarker templates. The context to the Freemarker template is a ICompilationUnit which allows fully access to named classes and their information. We are using it to generate DAOs for NoSQL databases, jersey client, tests, etc.
I think it can easily do what is required here.

Categories