2

I meet an issue with a class contained in a library that I use.

This issue comes when I want deserialize it.

Indeed, this class has a method names "getCopy" which returns a new instance of himself which contains this same method and call it still a StackOverFlowException on the following cycle :

at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:166)

at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)

at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:723)

public class Object {
   ...
   ObjectAttribute objectAttribute;
   ...

   public ObjectAttribute getObjectAttribute(){
      return this.objectAttribute
   }
   ...
}

public class ObjectAttribute{
   ...

   public ObjectAttribute getCopy{
      return copy(this) //return a new instance of himself
   }
   ...
}

Is there a way to ignore the method getCopy() like @JsonIgnoreAttribute("objectProperty.copy")?

cassiomolin
  • 124,154
  • 35
  • 280
  • 359
pacataque
  • 130
  • 12
  • Methods of the class are not being serialized, only fields are. If you are getting StackOverflowError then there must be a problem with the way you are trying to serialize/deserialize data. Provide more code. –  J.Kennsy Dec 16 '20 at 10:03
  • Thank you for your reply ! I'm not sure that "get" method are not call during serialization... I don't know what can I show you more. If I put a break point in my methode I can see that at each iteration, this method is called. – pacataque Dec 16 '20 at 14:41
  • I guess You are trying to SERIALIZE an object. And you can`t annotate this method by @JsonIgnore, as it 3-rd party class? – Pavel Chermyanin Dec 18 '20 at 13:12
  • Correct it's my problem. Else this 3rd Class should be serializable. – pacataque Dec 18 '20 at 13:23

5 Answers5

1

For this specific use case, when you have a class in a third party library that you are not able to modify, Jackson provides the Mix-in annotations.

The idea behind this concept is to provide a class that indicates how the serialization of another class should be accomplished.

For instance, consider the following mix-in class definition for your use case:

public abstract class ObjectAttributeMixIn{
   // You need to provide definitions for every property you need
   // to serialize, and the proper constructor if necessary
   ...

   // Ignore the getCopy method
   @JsonIgnore
   public abstract ObjectAttribute getCopy();

   ...
}

You can use the full set of Jackson annotations in the mix-in definitions.

Then, associate the mix-in with the ObjectAttribute class. You can use the instance of ObjectMapper you are using for serialization for this purpose:

objectMapper.addMixInAnnotations(ObjectAttribute.class, ObjectAttributeMixIn.class);

Yon can also register a custom module instead; please, see the relevant documentation.

jccampanero
  • 50,989
  • 3
  • 20
  • 49
0

for ignore method getCopy, just enough rename this method , e.g copy

every method start with get then serialized ,e.g if method name is getSomething then serialized to something: (return value by method))

so if you change method name to copy or copyInstance or every name without start by get then method not serialized

  • Thank you for your answer. The problem is that my Class is in an other lib, I haven't access to the source code. Else sure, I can change the name of my method or add @JSonIgnor on it but I can't in my case... – pacataque Dec 18 '20 at 15:15
0

You can override JsonSerializer and do specific logic for class

public class CustomSerializerForC extends JsonSerializer<C> {
   @Override
   public Class<C> handledType() {
       return C.class;
   }
  @Override
   public void serialize(C c, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
       String upperCase = c.getValue().toUpperCase();
       jsonGenerator.writeString(upperCase);
   }
}

And use Serializer in moudle used in ObjectMapper:

   SimpleModule module = new SimpleModule("MyCustomModule", new Version(1, 0, 0, null));
   module.addSerializer(new CustomSerializerForC());
   ObjectMapper mapper = new ObjectMapper();
   mapper.registerModule(module);
Ori Marko
  • 56,308
  • 23
  • 131
  • 233
0

You can register serializer and choose the fields you would like

 /**
 * We can not change source code so we are adding serializer for a specific type.
 *
 */
public static class JsonSpecificTypeSerializer extends JsonSerializer<SpecificType> {

    @Override
    public void serialize(SpecificType t, JsonGenerator jsonGen, SerializerProvider serializerProvider) throws IOException {
        jsonGen.writeStartObject();
        jsonGen.writeFieldName("field1");
        jsonGen.writeNumber(t.getield1());
        .......

        jsonGen.writeEndObject();
    }

}

/**
 * Customize jackson.
 *
 * adding configuration to jackson without overriding spring boot default conf.
 */
@Bean
public Jackson2ObjectMapperBuilderCustomizer customizeJackson() {
    return jacksonObjectMapperBuilder -> {
        jacksonObjectMapperBuilder.serializerByType(SpecificType.class,
                new JsonSpecificTypeSerializer());
    };
}
Itay wazana
  • 229
  • 2
  • 9
0

There are 2 ways I see how to figure out your issue:

  1. Write custom deserializer for you specific class and register it in Jackson mapper.
  2. Tune up global Jackson mapper to ignore class getters in auto-detection and use only fields.

Please try 2 way with following config:

ObjectMapper mapper = new ObjectMapper();

mapper.setVisibility(JsonMethod.ALL, Visibility.NONE);
mapper.setVisibility(JsonMethod.FIELD, Visibility.ANY);

If you decide to move forward with 1 way, please write here if you need help.

Dharman
  • 30,962
  • 25
  • 85
  • 135
eg04lt3r
  • 2,467
  • 14
  • 19