2017-02-13 31 views
1

Учитывая, что объект JSON имеет свойство mutable (например, метка), которое может быть либо примитивным значением (например, строкой), либо объектом. Гипотетический вариант использование может быть оберткой для множественного перевода метки:Свойство JSON для удаления объекта с объектом Jackson

{ 
    "label": "User name" 
} 

или

{ 
    "label": { 
     "one": "A label", 
     "other": "The labels" 
    } 
} 

Цель состоит в том, чтобы принести Jackson десериализации всегда возвращает фиксированную структуру на Java стороне. Таким образом, если примитивно значение придается оно всегда переводится на определенное имущество (например, другой) целевого POJO, то есть:

public class Translations { 
    @JsonDeserialize(using = PluralizedTranslationDeserializer.class) 
    public PluralizedTranslation label; 
} 

public class PluralizedTranslation { 
    public String one; 
    public String other; // used as default fields for primitive value 
} 

В настоящее время решается вопрос с помощью пользовательского JsonDeserializer, который проверяет, является ли свойство примитива или нет:

public class PluralizedTranslationDeserializer extends JsonDeserializer { 
    @Override 
    public PluralizedTranslation deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { 
     ObjectCodec oc = jsonParser.getCodec(); 
     JsonNode node = oc.readTree(jsonParser); 
     PluralizedTranslation translation; 

     if (node.isTextual()) { 
      translation = new PluralizedTranslation(); 
      translation.other = node.asText(); 
     } else { 
      translation = oc.treeToValue(node, PluralizedTranslation.class); 
     } 

     return translation; 
    } 
} 

есть ли более элегантный подход для обработки изменяемых свойств JSON без необходимости декодер, который работает на уровне узла?

+2

Этот вопрос не имеет ничего общего с изменчивостью. У вас только есть свойство и вы хотите каким-то образом десериализовать его. –

+0

@ Miha_x64 Я описал значение свойства как изменяемое, потому что тип его значения имеет [«ответственность или тенденция к изменению»] (https://en.oxforddictionaries.com/definition/mutability). Извините за вводящее в заблуждение прилагательное, вопрос, конечно, не связан с изменением объекта (Java). – dim

ответ

2

Вы можете сделать сеттер label более общим и добавить некоторую логику обработки двух случаев.

public class Translations { 
    // Fields omitted. 

    @JsonProperty("label") 
    public void setLabel(Object o) { 
     if (o instanceof String) { 
      // Handle the first case 
     } else if (o instanceof Map) { 
      // Handle the second case 
     } else { 
      throw new RuntimeException("Unsupported"); 
     } 
    } 
} 

Альтернативное решение, который помещает фабричный метод внутри PluralizedTranslation класса, оставляя Translations класс неизменным:

public class PluralizedTranslation { 
    public String one; 
    public String other; // used as default fields for primitive value 

    @JsonCreator 
    private PluralizedTranslation(Object obj) { 
     if (obj instanceof Map) { 
      Map map = (Map) obj; 
      one = (String) map.get("one"); 
      other = (String) map.get("other"); 
     } else if (obj instanceof String) { 
      other = (String) obj; 
     } else { 
      throw new RuntimeException("Unsupported"); 
     } 
    } 
} 

Обратите внимание, что конструктор может быть помечен как private для предотвращения непреднамеренного использования.

+0

Спасибо, что ответили. Действительно, это решение устраняет «JsonDeserializer». К сожалению, он также перемещает логику создания «PluralizedTranslation» в POJO. Следовательно, он будет получать зависимости от некоторых фабрик и/или от ObjectMapper, который не очень хорош. Кроме того, имея «частные» поля (которые были опущены в вопросе для простоты), нам нужно будет добавить дополнительную проверку для 'o instance PluralizedTranslation'. В общем, это альтернативное решение не выглядит намного более чистым для меня ... – dim

+0

@ dim: Я не могу полностью следовать вашим возражениям, но я постараюсь ответить на них. При любых обстоятельствах необходима какая-то фабрика. Я бы сказал, что включение его в класс облегчает понимание того, что происходит. Я не понимаю необходимости «o instanceof pluralizedTranslation». В обоих случаях создается экземпляр «PluralizedTranslation», так что это будет единственное, с чем должен работать пользователь класса. Я добавляю еще один подход, который я придумал, и это создает создание «PluralizedTranslation» в частном конструкторе, который я считаю довольно элегантным. – Henrik

+0

Я согласен с тем, что ваше решение довольно понятно. Мое первое возражение было связано с тем, что 'setLabel' должен иметь возможность принимать действительный экземпляр« PluralizedTranslation »(который в настоящее время вызывает« RuntimeException »), но это не проблема. 2-й: разумно использовать «ObjectMapper» вместо ручного отображения, что означает, что его нужно вводить в POJO. Здесь мне не комфортно.Однако ваши предложения действительны для данного простого случая, но я больше искал аннотацию магического @ @ JsonDefaultValue;). – dim