2016-09-06 2 views
2

У меня есть следующие Java Beans:Json полиморфизм с Джексоном и Json без объекта оболочки



    /** 
    * The top container. It uses generics. 
    */ 
    public class Response { 
     @JsonTypeInfo(
      use = JsonTypeInfo.Id.NAME, 
      include = JsonTypeInfo.As.WRAPPER_OBJECT, 
      property = "type" 
    ) 
     @JsonSubTypes({ 
     @JsonSubTypes.Type(name = "AContent", value = A.class), 
     @JsonSubTypes.Type(name = "BContent", value = B.class),   
     }) 
     private E object; 
    } 

    /** 
    * First type 
    */ 
    @JsonRootName("AContent") 
    public class A { 
     ... 
    } 

    /** 
    * Second type 
    */ 
    @JsonRootName("BContent") 
    public class B { 
     ... 
    } 

Когда запрос обрабатывается, я просто ожидать следующий вывод:

{ 
    AContent: { ...} 
} 

Однако , Я получаю следующий результат:

{ 
    object: { 
     AContent: { ...} 
    } 
} 

Элемент «AContent» завернут в элемент объекта. Я не хочу, чтобы объект-оболочка был общим. Я также не хочу устанавливать тип объекта непосредственно внутри общего объекта.

Я хотел бы вывести «AContent» непосредственно внутри корневого элемента.

Как мы можем достичь этого с Джексоном?

Заранее благодарю вас за помощь.

С наилучшими пожеланиями,

Желтая утка

+0

Что касается сериализации, вы всегда можете использовать собственный сериализатор, который пропускает _Request_ и переходит прямо к _object_, но десериализация это сложнее. – chimmi

+0

Я бы хотел, чтобы трикотаж/джексон автоматически сериализовал объект. Можно ли достичь этого с помощью аннотации jackson? – yellowduck

+0

Существует еще одно решение, если вы можете позволить себе ввести базовый объект _A_ и _B_. – chimmi

ответ

1

Так как вы сказали, что вы можете предоставить базовый объект для A и B решение будет:

@JsonSerialize(using = ResponseSerializer.class) 
public class Response<T> { 
    private T object; 
    ... 
} 

Базовый объект (другие должны расширять ее):

@JsonTypeInfo(
     use = JsonTypeInfo.Id.NAME, 
     include = JsonTypeInfo.As.WRAPPER_OBJECT 
) 
@JsonSubTypes({ 
     @JsonSubTypes.Type(name = "AContent", value = EntityA.class), 
     @JsonSubTypes.Type(name = "BContent", value = EntityB.class), 
}) 
public class Entity { 
    ... 
} 

И сериализатору:

public class ResponseSerializer extends JsonSerializer<Response> { 
    @Override 
    public void serialize(Response value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException { 
     Class<?> responseClass = value.getObject().getClass(); 
     JavaType responseJavaType = serializers.constructType(responseClass); 
     gen.writeStartObject(); 
     gen.writeFieldName(serializers.findTypeSerializer(responseJavaType).getTypeIdResolver().idFromValue(value.getObject())); 
     serializers.findValueSerializer(responseClass).serialize(value.getObject(), gen, serializers); 
     /* Here you must manually serialize other properties */ 
     /* Like gen.writeStringField("property", value.getProperty()); */ 
     gen.writeEndObject(); 
    } 
} 

P.S. Я удалил дополнительные аннотации, которые у вас были, что не имело никакого значения для вывода.

+0

Большое спасибо chimmi. Он отлично работает с общим базовым объектом с аннотациями JsonTypeInfo и JsonSubTypes и с аннотацией JsonValue по методу getObject(). – yellowduck

+0

Проблема с этим решением (аннотация jsonValue): я больше не мог видеть другие свойства в компоненте Request. Например, в классе Request, если я добавляю новый атрибут, он не будет отображаться в результате json. – yellowduck

+0

@yellowduck В вашем вопросе нет указаний на наличие других свойств в _Response_, поэтому я думал, что _JsonValue_ достаточно.Во всяком случае, Ive заменил мой ответ на один, используя пользовательский сериализатор, по крайней мере с этим вы можете сериализовать дополнительные свойства вручную. И, я боюсь, это лучшее решение, которое вы можете получить, по крайней мере, я могу это сделать. – chimmi

Смежные вопросы