#java #json #jackson
#java #json #джексон
Вопрос:
У меня есть заданный JSON:
{
"facility-no": "2011",
"standard-counter": [
{
"id": "0",
"type": "0",
"text": "Gebucht",
"free": "0",
"present": "0",
"percent": "100",
"max": "0",
"status": "Frei",
"status-value": "0"
}, ...
], ...
}
и я хочу, чтобы он десериализовался в мои классы…
Класс-оболочка:
public class Counters {
@JsonProperty("facility-no")
private String facilityId;
@JsonProperty("standard-counter")
private List<XCounter> xCounters;
}
Класс, реализующий объект, хранящийся в списке в классе-оболочке:
public class XCounter {
protected String id;
@JsonIgnore
public static final CounterTypeEnum type = CounterTypeEnum.X_COUNTER;
// standard amp; level counter properties
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
String text;
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
int free;
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
int present;
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
float percent;
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
int max;
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
String status;
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
@JsonProperty("status-value")
int statusValue;
...(all getters and setters...)
Вот мой счетчик:
public enum CounterTypeEnum {
X_COUNTER(0), Y_COUNTER(1), Z_COUNTER(2);
private int type;
private CounterTypeEnum(final int type) {
this.type = type;
}
public int getType() {
return this.type;
}
}
Однако я всегда получаю UnrecognizedPropertyException:
org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "type" (Class com.foo.bar.XCounter), not marked as ignorable
at [Source: java.io.StringReader@42077608; line: 1, column: 61] (through reference chain: com.foo.bar.Counters["standard-counter"]->com.foo.bar.XCounter["type"])
если я не использую @JsonIgnoreProperties(ignoreUnknown=true) на уровне класса нестандартных счетчиков.
Как я могу избежать этого исключения без использования @JsonIgnoreProperties(ignoreUnknown=true)?
Комментарии:
1. Почему вы
type
не хотите десериализоваться?2. Пожалуйста, проверьте, существует ли метод
getType()
получения, также он помечен @JsonProperty(«тип»)3. Как я уже говорил вам, JSON, который я получаю, исправлен. Свойство type может быть лишь одним из нескольких значений, которые я реализовал как перечисление. В моем классе XCounter это конечное / постоянное поле, которое нельзя установить. Следовательно, я не хочу, чтобы он был десериализован. Я думаю, что это ошибка проектирования при создании JSON в виде списка различных (XCounter, YCounter, …), в то время как все они имеют свойство «type» для указания типа счетчика. Я думаю, было бы лучше иметь либо один тип (класс) с атрибутом «type», либо иметь столько классов, сколько необходимо, без необходимости иметь свойство type.
4. Геттеры и сеттеры аннотируются, как вы предложили.
5. Простой ответ: не используйте Jackson. На самом деле пишу код. Люди тратят больше времени, пытаясь заставить Джексона работать, чем потребовалось бы, чтобы «просто сделать это».
Ответ №1:
Вы можете рассмотреть возможность замены вашего типа перечисления фактическим типом класса, использующим полиморфную десериализацию Джексона. В этом случае Jackson создаст экземпляр определенного типа в зависимости от значения свойства type .
Вот пример:
public class JacksonPolymorphic {
public static String JSON = "{n"
" "facility-no": "2011",n"
" "standard-counter": [n"
" {n"
" "id": "0",n"
" "type": "0",n"
" "text": "Gebucht",n"
" "free": "0",n"
" "present": "0",n"
" "percent": "100",n"
" "max": "0",n"
" "status": "Frei",n"
" "status-value": "0"n"
" }n"
"]n"
"}";
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
public static abstract class Counter {
private final String id;
public Counter(String id) {
this.id = id;
}
}
public static class Counters {
private final String facilityId;
private final List<Counter> counters;
public Counters(@JsonProperty("facility-no") String facilityId,
@JsonProperty("standard-counter") List<Counter> counters) {
this.facilityId = facilityId;
this.counters = counters;
}
@Override
public String toString() {
return "Counters{"
"facilityId='" facilityId '''
", counters=" counters
'}';
}
}
@JsonTypeName("0")
public static class XCounter extends Counter {
private final String text;
private final int free;
private final int present;
private final float percent;
private final int max;
private final String status;
private final int statusValue;
public XCounter(@JsonProperty("id") String id,
@JsonProperty("text") String text,
@JsonProperty("free") int free,
@JsonProperty("present") int present,
@JsonProperty("percent") float percent,
@JsonProperty("max") int max,
@JsonProperty("status") String status,
@JsonProperty("status-value") int statusValue) {
super(id);
this.text = text;
this.free = free;
this.present = present;
this.percent = percent;
this.max = max;
this.status = status;
this.statusValue = statusValue;
}
@Override
public String toString() {
return "XCounter{"
"text='" text '''
", free=" free
", present=" present
", percent=" percent
", max=" max
", status='" status '''
", statusValue=" statusValue
'}';
}
}
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.registerSubtypes(XCounter.class);
System.out.println(mapper.readValue(JSON, Counters.class));
}
}
Вывод:
Counters{facilityId='2011', counters=[XCounter{text='Gebucht', free=0, present=0, percent=100.0, max=0, status='Frei', statusValue=0}]}
Ответ №2:
Основная проблема здесь заключается в том, что во время десериализации де-сериализатор по умолчанию попытается сопоставить весь Json с вашим объектом. Но у него не будет подсказки относительно того, где должен быть отображен «тип».
Использование пользовательского сериализатора и десериализатора — хороший подход, если вы хотите, чтобы отображались только некоторые поля.
Надеюсь, это поможет!
Удачи
Ответ №3:
Если вы хотите, чтобы поле было десериализовано, но не сериализовано, вы должны использовать @JsonIgnore
в getter и объявлении атрибута, а @JsonProperty
также в setter при использовании Jackson