Jackson

Aus Wiki - Jochen Hammann
Zur Navigation springen Zur Suche springen


Implementierung eines TypeIdResolver

Der folgende Code-Ausschnitt zeigt die Implementierung eines TypeIdResolver.

public class MyTypeIdResolver implements TypeIdResolver
{
    // ============================== [Fields] ==============================
    // -------------------- [Private Fields] --------------------
    private JavaType baseType;
    // ============================== [Getter/Setter] ==============================
    // -------------------- [Public Getter/Setter] --------------------
    @Override
    public Id getMechanism()
    {
        return Id.CUSTOM;
    }
    // ============================== [Methods] ==============================
    // -------------------- [Public Methods] --------------------
    @Override
    public void init(JavaType baseType)
    {
        this.baseType = baseType;
    }
    @Override
    public String idFromValue(Object value)
    {
        return idFromValueAndType(value, value.getClass());
    }
    @Override
    public String idFromValueAndType(Object value, Class<?> suggestedType)
    {
        return suggestedType.getName();
    }
    @Override
    public String idFromBaseType()
    {
        return idFromValueAndType(null, this.baseType.getClass());
    }
    @Override
    public JavaType typeFromId(String id)
    {
        Class<?> resolvedClass = null;
        
        try
        {
            resolvedClass = ClassUtil.findClass(id);
        }
        catch (ClassNotFoundException e)
        {
            e.printStackTrace();
        }
        
        return TypeFactory.defaultInstance().constructSpecializedType(this.baseType, resolvedClass);
    }
}


Die entsprechende (Basis-)Klasse muss folgende Annotations spezifizieren.

@JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonTypeIdResolver(MyTypeIdResolver.class)
public abstract class AnalysisIntervalViewModel implements ViewModel
{
    ...    
}


Implementierung eines Custom-Serializers

Der folgende Code-Ausschnitt zeigt die Implementierung eines Custom-Serializers. Die Registrierung eines Serializers erfolgt über einen Context Resolver (siehe unten).

public class AppZonedDateTimeSerializer extends JsonSerializer<AppZonedDateTime>
{
    // ============================== [Methods] ==============================
    // -------------------- [Public Methods] --------------------
    /*
     * (non-Javadoc)
     * 
     * @see com.fasterxml.jackson.databind.JsonSerializer#serialize(java.lang.Object,
     * com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider)
     */
    @Override
    public void serialize(AppZonedDateTime value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException
    {
        jgen.writeStartObject();
        jgen.writeStringField("isoDateTime", value.getIsoDateTime());
        jgen.writeStringField("timeZoneIdTzDb", value.getTimeZoneIdTzDb());
        jgen.writeEndObject();
    }
}


Implementierung eines Custom-Deserializers

Der folgende Code-Ausschnitt zeigt die Implementierung eines Custom-Deserializers. Die Registrierung eines Deserializers erfolgt über einen Context Resolver (siehe unten).

public class AppZonedDateTimeDeserializer extends JsonDeserializer<AppZonedDateTime>
{
    // ============================== [Methods] ==============================
    // -------------------- [Public Methods] --------------------
    /*
     * (non-Javadoc)
     * 
     * @see
     * com.fasterxml.jackson.databind.JsonDeserializer#deserialize(com.fasterxml.jackson.core.JsonParser
     * , com.fasterxml.jackson.databind.DeserializationContext)
     */
    @Override
    public AppZonedDateTime deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException
    {
        JsonNode node = jp.getCodec().readTree(jp);
        String isoDateTime = node.get("isoDateTime").asText();
        String timeZone = node.get("timeZoneIdTzDb").asText();
        return new AppZonedDateTime("N/A", isoDateTime, timeZone);
    }


Implementierung eines ContextResolver bzw. Object Mapper Provider

Mit Hilfe eines Context Resolvers bzw. Object Mapper Provider ist es möglich Serializer und Deserializer im Jackson Framework zu registrieren.

@Provider
public class MyObjectMapperProvider implements ContextResolver<ObjectMapper>
{
    // ============================== [Fields] ==============================
    // -------------------- [Private Fields] --------------------
    private final ObjectMapper defaultObjectMapper;
    // ============================== [Construction / Destruction] ==============================
    // -------------------- [Public Construction / Destruction] --------------------
    public MyObjectMapperProvider()
    {
         SimpleModule module = new SimpleModule();
         module.addDeserializer(AppZonedDateTime.class, new AppZonedDateTimeDeserializer());
         module.addSerializer(AppZonedDateTime.class, new AppZonedDateTimeSerializer());
        
         this.defaultObjectMapper = new ObjectMapper();
         this.defaultObjectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
//         this.defaultObjectMapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
//         this.defaultObjectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
         this.defaultObjectMapper.registerModule(module);
    }
    // ============================== [Getter/Setter] ==============================
    // -------------------- [Public Getter/Setter] --------------------
    @Override
    public ObjectMapper getContext(Class<?> type)
    {
        return defaultObjectMapper;
    }
}


@JsonTypeInfo und @JsonSubTypes

An Beispielen soll die Verwendung der Annotations @JsonTypeInfo und @JsonSubTypes veranschaulicht werden. Der folgende Code-Ausschnitt wurde verwendet, JSON mit abgeleiteten Datentypen zwischen Java (Jersey inkl. Jackson) und .NET (WCF) auszutauschen.

@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "__type")
@JsonSubTypes({ @Type(value = DayViewModel.class, name = "DayStatic:#Servicetrace.Reporting"),
    @Type(value = WeekViewModel.class, name = "WeekStatic:#Servicetrace.Reporting"),
    @Type(value = MonthViewModel.class, name = "MonthStatic:#Servicetrace.Reporting"),
    @Type(value = QuarterViewModel.class, name = "QuarterStatic:#Servicetrace.Reporting"),
    @Type(value = YearViewModel.class, name = "YearStatic:#Servicetrace.Reporting"),
    @Type(value = CustomIntervalViewModel.class, name = "CustomStatic:#Servicetrace.Reporting"),
    @Type(value = TodayViewModel.class, name = "TodayDynamic:#Servicetrace.Reporting"),
    @Type(value = YesterdayViewModel.class, name = "YesterdayDynamic:#Servicetrace.Reporting"),
    @Type(value = CurrentWeekViewModel.class, name = "CurrentWeekDynamic:#Servicetrace.Reporting"),
    @Type(value = LastWeekViewModel.class, name = "LastWeekDynamic:#Servicetrace.Reporting"),
    @Type(value = CurrentMonthViewModel.class, name = "CurrentMonthDynamic:#Servicetrace.Reporting"),
    @Type(value = LastMonthViewModel.class, name = "LastMonthDynamic:#Servicetrace.Reporting"),
    @Type(value = CurrentQuarterViewModel.class, name = "CurrentQuarterDynamic:#Servicetrace.Reporting"),
    @Type(value = LastQuarterViewModel.class, name = "LastQuarterDynamic:#Servicetrace.Reporting"),
    @Type(value = CurrentYearViewModel.class, name = "CurrentYearDynamic:#Servicetrace.Reporting"),
    @Type(value = LastYearViewModel.class, name = "LastYearDynamic:#Servicetrace.Reporting"),
    @Type(value = LastHoursViewModel.class, name = "LastHoursDynamic:#Servicetrace.Reporting") })
public abstract class AnalysisIntervalViewModel implements ViewModel
{
    ...
}


Der folgende Code-Ausschnitt wurde verwendet, JSON mit abgeleiteten Datentypen zwischen einem Java Client und Java Server (jeweils Jersey inkl. Jackson) auszutauschen.

@JsonTypeInfo(use = Id.CLASS, include = As.PROPERTY, property = "@class")
public abstract class AnalysisConfigViewModel implements ViewModel
{
    ...
}