У меня есть строка json, которую я должен де-сериализовать до следующего класса
class Data <T> {
int found;
Class<T> hits
}
Как мне это сделать? Это обычный способ
mapper.readValue(jsonString, Data.class);
Но как я могу сказать, что означает T?
Ответы:
Вам необходимо создать
TypeReference
объект для каждого используемого универсального типа и использовать его для десериализации. Например -mapper.readValue(jsonString, new TypeReference<Data<String>>() {});
источник
Data<T>
это НЕ тип. Вы должны указать фактический класс; в остальном то же, что иData<Object>
.TypeReference
? это такcom.fasterxml.jackson.core.type
?Вы не можете этого сделать: вы должны указать полностью разрешенный тип, например
Data<MyType>
.T
это просто переменная, и это бессмысленно.Но если вы имеете в виду, что
T
это будет известно, но не статически, вам нужно создать эквивалентTypeReference
динамически. Возможно, это уже упоминалось в других упомянутых вопросах, но это должно выглядеть примерно так:public Data<T> read(InputStream json, Class<T> contentClass) { JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, contentClass); return mapper.readValue(json, type); }
источник
TypeReference
: вreturn mapper.readValue(json, clazz);
чем именно проблема?TypeFactory
.. Отредактирую свой ответ.Первое, что вы делаете, это сериализуете, а затем можете десериализовать.
поэтому, когда вы выполняете сериализацию, вы должны использовать,
@JsonTypeInfo
чтобы позволить Джексону записывать информацию о классе в ваши данные json. Вы можете сделать вот так:Class Data <T> { int found; @JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class") Class<T> hits }
Затем, когда вы десериализуете, вы обнаружите, что Джексон десериализовал ваши данные в класс, который ваша переменная фактически выполняет во время выполнения.
источник
Для класса Data <>
ObjectMapper mapper = new ObjectMapper(); JavaType type = mapper.getTypeFactory().constructParametrizedType(Data.class, Data.class, Parameter.class); Data<Parameter> dataParam = mapper.readValue(jsonString,type)
источник
Просто напишите статический метод в классе Util. Я читаю Json из файла. вы можете передать String также readValue
public static <T> T convertJsonToPOJO(String filePath, Class<?> target) throws JsonParseException, JsonMappingException, IOException, ClassNotFoundException { ObjectMapper objectMapper = new ObjectMapper(); return objectMapper.readValue(new File(filePath), objectMapper .getTypeFactory().constructCollectionType(List.class, Class.forName(target.getName()))); }
Применение:
List<TaskBean> list = Util.<List<TaskBean>>convertJsonToPOJO("E:/J2eeWorkspaces/az_workspace_svn/az-client-service/dir1/dir2/filename.json", TaskBean.class);
источник
Вы можете обернуть его в другой класс, который знает тип вашего универсального типа.
Например,
class Wrapper { private Data<Something> data; } mapper.readValue(jsonString, Wrapper.class);
Вот что-то конкретное. Вам нужна обертка для каждого овеществленного типа. В противном случае Джексон не знает, какие объекты создавать.
источник
В Jackson 2.5 появился элегантный способ решения, использующий метод TypeFactory.constructParametricType (Class параметризованный, Class ... parameterClasses), который позволяет напрямую определить Jackson
JavaType
, указав параметризованный класс и его параметризованные типы.Предположим, вы хотите выполнить десериализацию
Data<String>
, вы можете:// the json variable may be a String, an InputStream and so for... JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, String.class); Data<String> data = mapper.readValue(json, type);
Обратите внимание, что если бы в классе было объявлено несколько параметризованных типов, это было бы не сложнее:
class Data <T, U> { int found; Class<T> hits; List<U> list; }
Мы могли сделать:
источник
Строка JSON, которую необходимо десериализовать, должна содержать информацию о типе параметра
T
.Вам нужно будет поместить аннотации Джексона в каждый класс, который может быть передан в качестве параметра
T
классу,Data
чтобы информация о типе параметраT
могла быть прочитана / записана в строку JSON Джексоном.Предположим, что это
T
может быть любой класс, расширяющий абстрактный классResult
.class Data <T extends Result> { int found; Class<T> hits } @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT) @JsonSubTypes({ @JsonSubTypes.Type(value = ImageResult.class, name = "ImageResult"), @JsonSubTypes.Type(value = NewsResult.class, name = "NewsResult")}) public abstract class Result { } public class ImageResult extends Result { } public class NewsResult extends Result { }
После того, как каждый класс (или их общий супертип), который может быть передан в качестве параметра
T
, аннотирован, Джексон включит информацию о параметреT
в JSON. Затем такой JSON можно десериализовать, не зная параметраT
во время компиляции.Эта ссылка на документацию Джексона говорит о полиморфной десериализации, но также полезна для ответа на этот вопрос.
источник
public class Data<T> extends JsonDeserializer implements ContextualDeserializer { private Class<T> cls; public JsonDeserializer createContextual(DeserializationContext ctx, BeanProperty prop) throws JsonMappingException { cls = (Class<T>) ctx.getContextualType().getRawClass(); return this; } ... }
источник
если вы используете scala и знаете общий тип во время компиляции, но не хотите вручную передавать TypeReference везде во всех ваших API, вы можете использовать следующий код (с jackson 2.9.5):
def read[T](entityStream: InputStream)(implicit typeTag: WeakTypeTag[T]): T = { //nathang: all of this *crazy* scala reflection allows us to handle List[Seq[Map[Int,Value]]]] without passing // new TypeReference[List[Seq[Map[Int,Value]]]]](){} to the function def recursiveFindGenericClasses(t: Type): JavaType = { val current = typeTag.mirror.runtimeClass(t) if (t.typeArgs.isEmpty) { val noSubtypes = Seq.empty[Class[_]] factory.constructParametricType(current, noSubtypes:_*) } else { val genericSubtypes: Seq[JavaType] = t.typeArgs.map(recursiveFindGenericClasses) factory.constructParametricType(current, genericSubtypes:_*) } } val javaType = recursiveFindGenericClasses(typeTag.tpe) json.readValue[T](entityStream, javaType) }
который можно использовать так:
источник
Чтобы десериализовать общую JSON-строку в Java-объект с помощью Jackson, вам необходимо:
Чтобы определить класс JSON.
Выполните сопоставление атрибутов.
Окончательный код, протестированный и готовый к использованию:
static class MyJSON { private Map<String, Object> content = new HashMap<>(); @JsonAnySetter public void setContent(String key, Object value) { content.put(key, value); } } String json = "{\"City\":\"Prague\"}"; try { MyPOJO myPOJO = objectMapper.readValue(json, MyPOJO.class); String jsonAttVal = myPOJO.content.get("City").toString(); System.out.println(jsonAttVal); } catch (IOException e) { e.printStackTrace(); }
Важно:
@JsonAnySetter
аннотация является обязательной, она обеспечивает общий анализ JSON и заполнение.Для более сложных случаев с вложенными массивами см. Ссылку на Baeldung: https://www.baeldung.com/jackson-mapping-dynamic-object
источник
Пример не очень хорошего, но простого решения (не только для Джексона, но и для Spring RestTemplate и т. Д.):
Set<MyClass> res = new HashSet<>(); objectMapper.readValue(json, res.getClass());
источник