web-dev-qa-db-fra.com

Comment accéder à la sérialisation jackson par défaut dans un sérialiseur personnalisé

Je souhaite créer un sérialiseur personnalisé qui effectue un travail minime, puis laisse le reste pour la sérialisation par défaut. 

Par exemple:

@JsonSerialize(using = MyClassSerializer.class)
public class MyClass {
  ...
}

public class MyClassSerializer extends JsonSerializer<MyClass> {
    @Override
    public void serialize(MyClass myClass, JsonGenerator generator, 
                          SerializerProvider provider) 
            throws JsonGenerationException, IOException {
        if (myClass.getSomeProperty() == someCalculationResult) {
            provider.setAttribute("special", true);
        }
        generator.writeObject(myClass);
    }  
}

Avec l'idée de créer d'autres sérialiseurs personnalisés pour les objets agrégés qui se comportent différemment en fonction de la valeur de l'attribut "speical". Cependant, le code ci-dessus ne fonctionne pas, car il entre sans surprise dans une récursion infinie.

Y a-t-il un moyen de dire à Jackson d'utiliser la sérialisation par défaut une fois l'attribut défini? Je ne veux pas vraiment énumérer toutes les propriétés, comme beaucoup de sérialiseurs personnalisés, car la classe est assez complexe et je ne souhaite pas avoir à effectuer une double maintenance avec le sérialiseur chaque fois que je change de classe.

17
DavidA

UnBeanSerializerModifiervous donnera accès à la sérialisation par défaut.

Injecter un sérialiseur par défaut dans le sérialiseur personnalisé

public class MyClassSerializer extends JsonSerializer<MyClass> {
    private final JsonSerializer<Object> defaultSerializer;

    public MyClassSerializer(JsonSerializer<Object> defaultSerializer) {
        this.defaultSerializer = checkNotNull(defaultSerializer);
    }

    @Override
    public void serialize(MyClass myclass, JsonGenerator gen, SerializerProvider provider) throws IOException {
        if (myclass.getSomeProperty() == true) {
            provider.setAttribute("special", true);
        }
        defaultSerializer.serialize(myclass, gen, provider);
    }
}

Créer une BeanSerializerModifier pour MyClass

public class MyClassSerializerModifier extends BeanSerializerModifier {
    @Override
    public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {
        if (beanDesc.getBeanClass() == MySpecificClass.class) {
            return new MyClassSerializer((JsonSerializer<Object>) serializer);
        }
        return serializer;
    }
}

Enregistrez le modificateur de sérialiseur

ObjectMapper om = new ObjectMapper()
        .registerModule(new SimpleModule()
                .setSerializerModifier(new MyClassSerializerModifier()));
21
Sam Berry
@JsonSerialize(using = MyClassSerializer.class)
public class MyClass {
...
}

public class MyClassSerializer extends JsonSerializer<MyClass> {
    @Override
     public void serialize(MyClass myClass, JsonGenerator generator, 
                      SerializerProvider provider) 
        throws JsonGenerationException, IOException {
        if (myClass.getSomeProperty() == someCalculationResult) {
            provider.setAttribute("special", true);
        }
        provider.defaultSerializeValue(myClass, generator);
    }  
}

si vous écrivez simplement un objet comme d'habitude, utilisez ce qui précède

5
LawrenceMouarkach

Pour ajouter à la réponse choisie, l’implémentation du sérialiseur peut également devoir implémenter les interfaces ContextualSerializer et ResolvableSerializer. Jetez un coup d’œil à un problème connexe ici https://github.com/FasterXML/jackson-dataformat-xml/issues/259

public class MyClassSerializer extends JsonSerializer<MyClass>
    implements ContextualSerializer, ResolvableSerializer {
private final JsonSerializer<Object> defaultSerializer;

public MyClassSerializer(JsonSerializer<Object> defaultSerializer) {
    this.defaultSerializer = checkNotNull(defaultSerializer);
}

@Override
public void serialize(MyClass myclass, JsonGenerator gen, SerializerProvider provider)
        throws IOException {
    if (myclass.getSomeProperty() == true) {
        provider.setAttribute("special", true);
    }
    defaultSerializer.serialize(myclass, gen, provider);
}

@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
        throws JsonMappingException {
    if (defaultSerializer instanceof ContextualSerializer) {
        JsonSerializer<?> contextual = ((ContextualSerializer)defaultSerializer).createContextual(prov, property);
        return new MyClassSerializer((JsonSerializer<Object>)contextual);
    }
    return new MyClassSerializer(defaultSerializer);
}

@Override
public void resolve(SerializerProvider provider) throws JsonMappingException {
    if (defaultSerializer instanceof ResolvableSerializer) {
        ((ResolvableSerializer)defaultSerializer).resolve(provider);
    }
}

}

0
Pawel Zieminski

Vous pouvez utiliser @JsonGetter au lieu d'utiliser un sérialiseur personnalisé si c'est le seul changement que vous souhaitez apporter.

public class MyClass{

    @JsonGetter("special")
    protected boolean getSpecialForJackson() {
        return myClass.getSomeProperty() == someCalculationResult;
    }

}
0
Alex Block