Подтвердить что ты не робот

Джексон - десериализовать с помощью универсального класса

У меня есть строка JSON, который я должен deSerialize для следующего класса

class Data <T> {
    int found;
    Class<T> hits
}

Как мне это сделать? Это обычный способ

mapper.readValue(jsonString, Data.class);

Но как мне упомянуть, что означает Т?

4b9b3361

Ответ 1

Вам нужно создать объект TypeReference для каждого используемого вами типового типа и использовать его для десериализации. Например,

mapper.readValue(jsonString, new TypeReference<Data<String>>() {});

Ответ 2

Вы не можете сделать это: вы должны указать полностью разрешенный тип, например, 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);
}

Ответ 3

Первое, что вы делаете, - сериализовать, тогда вы можете выполнить десериализацию.
поэтому, когда вы выполняете сериализацию, вы должны использовать @JsonTypeInfo, чтобы позволить jsonson записывать информацию о классе в ваши json-данные. Что вы можете сделать, так это:

Class Data <T> {
    int found;
    @JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class")
    Class<T> hits
}

Затем, когда вы выполните десериализацию, вы обнаружите, что джексон десериализует ваши данные в класс, который ваша переменная на самом деле находится во время выполнения.

Ответ 4

Для класса данных <>

ObjectMapper mapper = new ObjectMapper();
JavaType type = mapper.getTypeFactory().constructParametrizedType(Data.class, Data.class, Parameter.class);
Data<Parameter> dataParam = mapper.readValue(jsonString,type)

Ответ 5

Просто напишите статический метод в классе 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);

Ответ 6

Вы можете перенести его в другой класс, который знает тип вашего общего типа.

Например,

class Wrapper {
 private Data<Something> data;
}
mapper.readValue(jsonString, Wrapper.class);

Здесь что-то конкретный тип. Вам нужна обертка для каждого типа. В противном случае Джексон не знает, какие объекты создавать.

Ответ 7

Строка 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 во время компиляции.
Эта ссылка на документацию Джексона говорит о полиморфной десериализации, но полезно также обратиться к этому вопросу.

Ответ 8

С Jackson 2.5, элегантный способ решить, используя TypeFactory.constructParametricType(Class параметризованный, Class... parameterClasses) метод, который позволяет строго определить Джексона 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;
}

Мы могли бы сделать:

JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, String.class, Integer);
Data<String, Integer> data = mapper.readValue(json, type);

Ответ 9

если вы используете scala и знаете универсальный тип во время компиляции, но не хотите вручную передавать TypeReference везде во всех ваших приложениях, вы можете использовать следующий код (с 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)
  }

который можно использовать так:

read[List[Map[Int, SomethingToSerialize]]](inputStream)

Ответ 10

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;
    }
    ...
 }