web-dev-qa-db-de.com

Zugriff auf die Standard-Jackson-Serialisierung in einem benutzerdefinierten Serializer

Ich möchte einen benutzerdefinierten Serialisierer erstellen, der eine kleine Arbeit erledigt und den Rest für die Standardserialisierung übrig lässt. 

Zum Beispiel:

@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);
    }  
}

Mit der Idee, andere benutzerdefinierte Serialisierer für aggregierte Objekte zu erstellen, die sich basierend auf dem Attributwert 'speical' unterschiedlich verhalten. Der obige Code funktioniert jedoch nicht, da er nicht überraschend in eine unendliche Rekursion geht.

Gibt es eine Möglichkeit, jackson die Standard-Serialisierung zu verwenden, sobald ich das Attribut eingestellt habe? Ich möchte nicht wirklich alle Eigenschaften aufzählen, wie viele benutzerdefinierte Serialisierer, da die Klasse ziemlich komplex ist und ich nicht jedes Mal, wenn ich die Klasse wechsle, den Serializer doppelt warten muss.

17
DavidA

EineBeanSerializerModifierermöglicht Ihnen den Zugriff auf die Standardserialisierung.

Fügen Sie einen Standard-Serializer in den benutzerdefinierten Serializer ein

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);
    }
}

Erstellen Sie eine BeanSerializerModifier für 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;
    }
}

Registrieren Sie den Modifikator für den Serialisierer

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);
    }  
}

wenn Sie nur ein Objekt wie üblich schreiben, verwenden Sie das obige

5

Um die gewählte Antwort hinzuzufügen, muss die Implementierung des Serialisierers möglicherweise auch ContextualSerializer- und ResolvableSerializer-Schnittstellen implementieren. Bitte sehen Sie sich hier ein verwandtes Problem an 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

Sie können @JsonGetter anstelle eines benutzerdefinierten Serializers verwenden, wenn dies die einzige Änderung ist, die Sie vornehmen möchten.

public class MyClass{

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

}
0
Alex Block