Tengo que usarlo como TypeReference <Data <T>> () {} ... Pero recibo el siguiente error: no puedo acceder al java.lang.class.Class () privado de java.lang.class. Error al establecer el acceso. No se puede hacer accesible un constructor java.lang.Class
gnjago
No, no Data<T>, eso NO es un tipo. Debe especificar la clase real; de lo contrario es lo mismo que Data<Object>.
StaxMan
18
¿Qué pasa si no sé qué clase es hasta el tiempo de ejecución? Obtendré la clase como parámetro durante el tiempo de ejecución. Al igual que este <T> void deSerialize público (Class <T> clazz {ObjectMapper mapper = new ObjectMapper (); mapper.readValue (jsonString, new TypeReference <Json <T>> () {});}
¿Cuál es el nombre completo del paquete TypeReference? ¿es com.fasterxml.jackson.core.type?
Lei Yang
88
No puede hacer eso: debe especificar el tipo totalmente resuelto, como Data<MyType>. Tes solo una variable, y como no tiene sentido.
Pero si quiere decir que Tse sabrá, pero no estáticamente, debe crear un equivalente de TypeReferenceforma dinámica. Otras preguntas a las que se hace referencia ya pueden mencionar esto, pero debería verse así:
publicData<T> read(InputStream json,Class<T> contentClass){JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, contentClass);return mapper.readValue(json, type);}
¿Qué pasa si no sé qué clase es hasta el tiempo de ejecución? Obtendré la clase como parámetro durante el tiempo de ejecución. Como este <T> void deSerialize público (Class <T> clazz {ObjectMapper mapper = new ObjectMapper (); mapper.readValue (jsonString, new TypeReference <Json <T>> () {});}
Luego, simplemente pase la clase como está, sin necesidad de TypeReference: return mapper.readValue(json, clazz);¿Cuál es exactamente el problema aquí?
StaxMan
2
El problema es que "Datos" es una clase genérica. Necesito especificar qué tipo T es en tiempo de ejecución. El parámetro clazz es lo que usamos en tiempo de ejecución. Entonces, ¿cómo llamar a readValue? llamarlo con la nueva TypeReference> Json <T>> no funciona La pregunta completa está aquí stackoverflow.com/questions/11659844/…
gnjago
2
Okay. Entonces necesitas usar TypeFactory... Editaré mi respuesta.
StaxMan
30
Lo primero que debe hacer es serializar, luego puede deserializar.
así que cuando serialices, deberías usar @JsonTypeInfopara dejar que Jackson escriba información de clase en tus datos json Lo que puedes hacer es así:
Luego, cuando deserialice, encontrará que Jackson ha deserializado sus datos en una clase en la que sus aciertos variables están en tiempo de ejecución.
no funciona, obteniendo el siguiente error com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Falta el tipo de identificación al intentar resolver el subtipo de [tipo simple, clase java.lang.Object]: falta la propiedad de identificación de tipo '@clase' (para POJO propiedad 'datos')
gaurav9620
15
Para la clase Datos <>
ObjectMapper mapper =newObjectMapper();JavaType type = mapper.getTypeFactory().constructParametrizedType(Data.class,Data.class,Parameter.class);Data<Parameter> dataParam = mapper.readValue(jsonString,type)
Simplemente escriba un método estático en la clase Util. Estoy leyendo un Json de un archivo. puedes darle String también a readValue
publicstatic<T> T convertJsonToPOJO(String filePath,Class<?> target)throwsJsonParseException,JsonMappingException,IOException,ClassNotFoundException{ObjectMapper objectMapper =newObjectMapper();return objectMapper.readValue(newFile(filePath), objectMapper .getTypeFactory().constructCollectionType(List.class,Class.forName(target.getName())));}
Uso:
List<TaskBean> list =Util.<List<TaskBean>>convertJsonToPOJO("E:/J2eeWorkspaces/az_workspace_svn/az-client-service/dir1/dir2/filename.json",TaskBean.class);
La cadena JSON que debe ser deserializada tendrá que contener la información de tipo sobre el parámetro T.
Tendrá que poner anotaciones de Jackson en cada clase que se pueda pasar como parámetro Ta clase Datapara que TJackson pueda leer / escribir la información del tipo sobre el tipo de parámetro .
Supongamos que Tpuede ser cualquier clase que extienda la clase abstracta Result.
classData<T extendsResult>{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")})publicabstractclassResult{}publicclassImageResultextendsResult{}publicclassNewsResultextendsResult{}
Una vez que T se anota cada clase (o su supertipo común) que se puede pasar como parámetro , Jackson incluirá información sobre el parámetro Ten el JSON. Tal JSON se puede deserializar sin conocer el parámetro Ten tiempo de compilación.
Este enlace de documentación de Jackson habla sobre la deserialización polimórfica, pero también es útil hacer referencia a esta pregunta.
Suponiendo que desea deserializarse Data<String>, puede hacer:
// 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);
Tenga en cuenta que si la clase declara múltiples tipos parametrizados, no sería realmente más difícil:
JavaType type = mapper.getTypeFactory().constructParametricType(Data.class,String.class,Integer);Data<String,Integer> data = mapper.readValue(json, type);
Impresionante, gracias funcionó para mí. Con la referencia de tipo, obtuve una excepción de difusión de clase del mapa al objeto específico, pero esto realmente hace el trabajo.
si está usando scala y conoce el tipo genérico en tiempo de compilación, pero no desea pasar manualmente TypeReference a todas partes en todas sus aplicaciones, puede usar el siguiente código (con 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)}
Respuestas:
Debe crear un
TypeReference
objeto para cada tipo genérico que use y usarlo para la deserialización. Por ejemplo -fuente
Data<T>
, eso NO es un tipo. Debe especificar la clase real; de lo contrario es lo mismo queData<Object>
.TypeReference
? ¿escom.fasterxml.jackson.core.type
?No puede hacer eso: debe especificar el tipo totalmente resuelto, como
Data<MyType>
.T
es solo una variable, y como no tiene sentido.Pero si quiere decir que
T
se sabrá, pero no estáticamente, debe crear un equivalente deTypeReference
forma dinámica. Otras preguntas a las que se hace referencia ya pueden mencionar esto, pero debería verse así:fuente
TypeReference
:return mapper.readValue(json, clazz);
¿Cuál es exactamente el problema aquí?TypeFactory
... Editaré mi respuesta.Lo primero que debe hacer es serializar, luego puede deserializar.
así que cuando serialices, deberías usar
@JsonTypeInfo
para dejar que Jackson escriba información de clase en tus datos json Lo que puedes hacer es así:Luego, cuando deserialice, encontrará que Jackson ha deserializado sus datos en una clase en la que sus aciertos variables están en tiempo de ejecución.
fuente
Para la clase Datos <>
fuente
Simplemente escriba un método estático en la clase Util. Estoy leyendo un Json de un archivo. puedes darle String también a readValue
Uso:
fuente
Puede envolverlo en otra clase que conozca el tipo de su tipo genérico.
P.ej,
Aquí algo es un tipo concreto. Necesita un contenedor por tipo reificado. De lo contrario, Jackson no sabe qué objetos crear.
fuente
La cadena JSON que debe ser deserializada tendrá que contener la información de tipo sobre el parámetro
T
.Tendrá que poner anotaciones de Jackson en cada clase que se pueda pasar como parámetro
T
a claseData
para queT
Jackson pueda leer / escribir la información del tipo sobre el tipo de parámetro .Supongamos que
T
puede ser cualquier clase que extienda la clase abstractaResult
.Una vez que
T
se anota cada clase (o su supertipo común) que se puede pasar como parámetro , Jackson incluirá información sobre el parámetroT
en el JSON. Tal JSON se puede deserializar sin conocer el parámetroT
en tiempo de compilación.Este enlace de documentación de Jackson habla sobre la deserialización polimórfica, pero también es útil hacer referencia a esta pregunta.
fuente
Desde Jackson 2.5, una forma elegante de resolver usando el método TypeFactory.constructParametricType (Class parametrized, Class ... parameterClasses) que permite definir de forma recta un Jackson
JavaType
al especificar la clase parametrizada y sus tipos parametrizados.Suponiendo que desea deserializarse
Data<String>
, puede hacer:Tenga en cuenta que si la clase declara múltiples tipos parametrizados, no sería realmente más difícil:
Podríamos hacer :
fuente
fuente
si está usando scala y conoce el tipo genérico en tiempo de compilación, pero no desea pasar manualmente TypeReference a todas partes en todas sus aplicaciones, puede usar el siguiente código (con jackson 2.9.5):
que se puede usar así:
fuente
Para deserializar una cadena JSON genérica a un objeto Java con Jackson, necesita:
Para definir una clase JSON.
Realizar un mapeo de atributos.
Código final, probado y listo para usar:
Importante: la
@JsonAnySetter
anotación es obligatoria, garantiza un análisis genérico de JSON y una población.Para casos más complicados con matrices anidadas, consulte la referencia de Baeldung: https://www.baeldung.com/jackson-mapping-dynamic-object
fuente
Ejemplo de decisión no muy buena, pero simple (no solo para Jackson, también para Spring RestTemplate, etc.):
fuente