У меня есть два класса Java, которые я хочу сериализовать в JSON с помощью Джексона:
public class User {
public final int id;
public final String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
}
public class Item {
public final int id;
public final String itemNr;
public final User createdBy;
public Item(int id, String itemNr, User createdBy) {
this.id = id;
this.itemNr = itemNr;
this.createdBy = createdBy;
}
}
Я хочу сериализовать элемент в этот JSON:
{"id":7, "itemNr":"TEST", "createdBy":3}
с сериализованным пользователем, чтобы включить только id
. Я также смогу серилизовать все пользовательские объекты в JSON, например:
{"id":3, "name": "Jonas", "email": "jonas@example.com"}
Итак, я предполагаю, что мне нужно написать собственный сериализатор для Item
и попробовать это:
public class ItemSerializer extends JsonSerializer<Item> {
@Override
public void serialize(Item value, JsonGenerator jgen,
SerializerProvider provider) throws IOException,
JsonProcessingException {
jgen.writeStartObject();
jgen.writeNumberField("id", value.id);
jgen.writeNumberField("itemNr", value.itemNr);
jgen.writeNumberField("createdBy", value.user.id);
jgen.writeEndObject();
}
}
Я сериализую JSON с помощью этого кода из Jackson How-to: Custom Serializers :
ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule("SimpleModule",
new Version(1,0,0,null));
simpleModule.addSerializer(new ItemSerializer());
mapper.registerModule(simpleModule);
StringWriter writer = new StringWriter();
try {
mapper.writeValue(writer, myItem);
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Но я получаю такую ошибку:
Exception in thread "main" java.lang.IllegalArgumentException: JsonSerializer of type com.example.ItemSerializer does not define valid handledType() (use alternative registration method?)
at org.codehaus.jackson.map.module.SimpleSerializers.addSerializer(SimpleSerializers.java:62)
at org.codehaus.jackson.map.module.SimpleModule.addSerializer(SimpleModule.java:54)
at com.example.JsonTest.main(JsonTest.java:54)
Как я могу использовать собственный сериализатор с Джексоном?
Вот как я бы сделал это с Gson:
public class UserAdapter implements JsonSerializer<User> {
@Override
public JsonElement serialize(User src, java.lang.reflect.Type typeOfSrc,
JsonSerializationContext context) {
return new JsonPrimitive(src.id);
}
}
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(User.class, new UserAdapter());
Gson gson = builder.create();
String json = gson.toJson(myItem);
System.out.println("JSON: "+json);
Но мне нужно сделать это с Джексоном сейчас, поскольку у Gson нет поддержки интерфейсов.
java
json
serialization
jackson
Йонас
источник
источник
Item
? У меня проблема, когда мой метод контроллера возвращает стандартный сериализованный объектTypeA
, но для другого конкретного метода контроллера я хочу сериализовать его иначе. Как бы это выглядело?Ответы:
Как уже упоминалось, @JsonValue - хороший способ. Но если вы не возражаете против настраиваемого сериализатора, нет необходимости писать его для Item, а лучше для User - в таком случае это будет так просто:
Еще одна возможность - реализовать
JsonSerializable
, и в этом случае регистрация не требуется.Что касается ошибки; это странно - вы, вероятно, захотите перейти на более позднюю версию. Но также безопаснее расширять,
org.codehaus.jackson.map.ser.SerializerBase
поскольку он будет иметь стандартные реализации несущественных методов (то есть все, кроме фактического вызова сериализации).источник
Exception in thread "main" java.lang.IllegalArgumentException: JsonSerializer of type com.example.JsonTest$UserSerilizer does not define valid handledType() (use alternative registration method?) at org.codehaus.jackson.map.module.SimpleSerializers.addSerializer(SimpleSerializers.java:62) at org.codehaus.jackson.map.module.SimpleModule.addSerializer(SimpleModule.java:54) at com.example.JsonTest.<init>(JsonTest.java:27) at com.exampple.JsonTest.main(JsonTest.java:102)
Вы можете поместить
@JsonSerialize(using = CustomDateSerializer.class)
поверх любого поля даты сериализуемого объекта.источник
@JsonSerialize(contentUsing= ...)
при аннотировании Коллекций (например@JsonSerialize(contentUsing= CustomDateSerializer.class) List<Date> dates
)Я тоже пытался сделать это, и в примере кода на веб-странице Джексона есть ошибка, из-за которой не удается включить type (
.class
) в вызовaddSerializer()
метода, который должен выглядеть следующим образом:Другими словами, это строки, которые создают
simpleModule
и добавляют сериализатор (с закомментированной предыдущей неправильной строкой):К вашему сведению: вот ссылка на правильный пример кода: http://wiki.fasterxml.com/JacksonFeatureModules
источник
Используйте @JsonValue:
@JsonValue работает только с методами, поэтому вы должны добавить метод getId. Вы должны иметь возможность вообще пропустить свой собственный сериализатор.
источник
Я написал пример настраиваемой
Timestamp.class
сериализации / десериализации, но вы можете использовать его для чего захотите.При создании сопоставителя объектов сделайте что-то вроде этого:
например,
java ee
вы можете инициализировать его следующим образом:где сериализатор должен быть примерно таким:
и десериализатор примерно так:
источник
Это шаблоны поведения, которые я заметил, пытаясь понять сериализацию Джексона.
1) Предположим, есть объект Класс и класс Студент. Для простоты я сделал все публичным и окончательным.
2) Предположим, что это сериализаторы, которые мы используем для сериализации объектов в JSON. WriteObjectField использует собственный сериализатор объекта, если он зарегистрирован в преобразователе объектов; если нет, то он сериализует его как POJO. WriteNumberField принимает только примитивы в качестве аргументов.
3) Зарегистрируйте только DoubleSerializer с шаблоном вывода
###,##0.000
DecimalFormat в SimpleModule, и результат будет:Вы можете видеть, что сериализация POJO различает double и Double, используя DoubleSerialzer для Doubles и используя обычный формат String для double.
4) Зарегистрируйте DoubleSerializer и ClassroomSerializer без StudentSerializer. Мы ожидаем, что результат будет таким, что если мы напишем double как объект, он будет вести себя как Double, а если мы напишем Double как число, он будет вести себя как double. Переменная экземпляра Student должна быть записана как POJO и следовать приведенному выше шаблону, поскольку она не регистрируется.
5) Зарегистрируйте все сериализаторы. Результат:
именно так, как ожидалось.
Еще одно важное замечание: если у вас есть несколько сериализаторов для одного и того же класса, зарегистрированных в одном и том же модуле, то модуль выберет сериализатор для этого класса, который был добавлен в список последним. Это не следует использовать - это сбивает с толку, и я не уверен, насколько это последовательно
Мораль: если вы хотите настроить сериализацию примитивов в своем объекте, вы должны написать свой собственный сериализатор для объекта. Вы не можете полагаться на сериализацию POJO Jackson.
источник
Представления JSON Джексона могут быть более простым способом достижения ваших требований, особенно если у вас есть некоторая гибкость в вашем формате JSON.
Если
{"id":7, "itemNr":"TEST", "createdBy":{id:3}}
это приемлемое представление, то этого будет очень легко достичь с помощью очень небольшого кода.Вы должны просто аннотировать поле имени пользователя как часть представления и указать другое представление в запросе сериализации (неаннотированные поля будут включены по умолчанию)
Например: Определите представления:
Аннотируйте пользователя:
И сериализуйте запрос представления, которое не содержит поля, которое вы хотите скрыть (по умолчанию неаннотированные поля сериализуются):
источник
createdBy
значение вместо объекта?setSerializationView()
кажется устаревшим, поэтому я использовалmapper.viewWriter(JacksonViews.ItemView.class).writeValue(writer, myItem);
вместо этого.В моем случае (Spring 3.2.4 и Jackson 2.3.1) конфигурация XML для настраиваемого сериализатора:
был чем-то необъяснимым образом перезаписан до значения по умолчанию.
Это сработало для меня:
CustomObject.java
CustomObjectSerializer.java
В
<mvc:message-converters>(...)</mvc:message-converters>
моем решении конфигурация XML ( ) не требуется.источник
Если ваше единственное требование в пользовательском сериализаторе - пропустить сериализацию
name
поляUser
, отметьте его как временное . Джексон не будет сериализовать или десериализовать переходные процессы поля.[см. также: Почему в Java есть временные поля? ]
источник
User
-классе? Но я тоже буду сериализовать все пользовательские объекты. Например, сначала сериализуйте только всеitems
(толькоuserId
в качестве ссылки на пользовательский объект), а затем сериализуйте всеusers
. В этом случае я не могу отметить поля вUser
-классе.handledType()
в документации, на которую я ссылаюсь, ничего не говорится о методе, и когда Eclipse генерирует методы для реализации, неhandledType()
генерируется, поэтому я запутался.Вам нужно переопределить метод handledType, и все будет работать
источник
Проблема в вашем случае заключается в том, что в ItemSerializer отсутствует метод handledType (), который необходимо переопределить из JsonSerializer
Следовательно, вы получаете явную ошибку, что handledType () не определен
Надеюсь, это кому-то поможет. Спасибо, что прочитали мой ответ.
источник