[英]Json deserializer that works across different classes in java
I am trying to create an @JsonDeserializer that will work across classes. 我试图创建一个@JsonDeserializer,将跨类工作。 I am using JAX-RS and the incoming json string will have fields in snake case. 我正在使用JAX-RS,传入的json字符串将在蛇形情况下包含字段。 I want to override the json deserialization so that my java objects do not have snake-case fields. 我想覆盖json反序列化,以便我的java对象没有蛇形字段。 Since the creation of the java object is happening within JAX-RS, I am using the @JsonDeserializer annotation on all my request classes. 由于Java对象的创建是在JAX-RS中进行的,因此我在所有请求类上使用@JsonDeserializer批注。 My current implementation has a generic base class, but I need to extend it for all the concrete classes so that I can pass in the actual class I want to create. 我当前的实现有一个通用的基类,但是我需要将其扩展到所有具体的类,以便可以传入想要创建的实际类。 Is there any way to do this more generically? 有什么办法可以更一般地做到这一点吗?
For example, I have multiple request objects like this: 例如,我有多个这样的请求对象:
@JsonDeserialize(using = MyRequestDeserializer.class)
public class MyRequest {
....
}
I have created a generic deserializer like so: 我创建了一个通用的反序列化器,如下所示:
public class GenericRequestDeserializer extends JsonDeserializer<Object> {
private static ObjectMapper objectMapper = new ObjectMapper();
@Override
public Object deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
return null;
}
protected Object deserializeIt(JsonParser jsonParser, Class cls) {
try {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
Iterator<String> fieldNames = node.fieldNames();
Object object = cls.newInstance();
while(fieldNames.hasNext()) {
String fieldName = fieldNames.next();
JsonNode value = node.get(fieldName);
String newFieldName = convertFieldName(fieldName);
//TODO: currently failing if I do not find a field, should the exception be swallowed?
Class returnType = object.getClass().getMethod("get" + newFieldName).getReturnType();
Method setMethod = object.getClass().getMethod("set" + newFieldName, returnType);
Object valueToSet = null;
if(value.isTextual()) {
valueToSet = value.asText();
} else if(value.isContainerNode()) {
valueToSet = objectMapper.readValue(value.toString(), returnType);
} else if (value.isInt()) {
valueToSet = value.asInt();
}
setMethod.invoke(object, valueToSet);
}
return object;
} catch (Exception e) {
throw new TokenizationException(GatewayConstants.STATUS_SYSTEM_ERROR,
"Error in deserializeIt for " + cls.getSimpleName() + " caused by " + e.getMessage(), e);
}
}
private String convertFieldName(String fieldName) {
StringBuilder newFieldName = new StringBuilder();
int length = fieldName.length();
boolean capitalize = true; //first character should be capitalized
for(int i = 0; i < length; i++) {
char current = fieldName.charAt(i);
if(current == '_') {
//remove the underscore and capitalize the next character in line
capitalize = true;
} else if(capitalize) {
newFieldName.append(Character.toUpperCase(current));
capitalize = false;
} else {
newFieldName.append(current);
}
}
return newFieldName.toString();
}
} }
But I still need to create a new class per Request in order to pass in the proper class to create: 但是我仍然需要为每个请求创建一个新类,以便传递适当的类来创建:
public class MyRequestDeserializer extends GenericRequestDeserializer {
@Override
public Object deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
return deserializeIt(jsonParser, MyRequest.class);
}
}
Is there any way to get rid of all the MyRequestDeserializer classes? 有什么方法可以摆脱所有MyRequestDeserializer类? In other words, can the GenericRequestDeserializer figure out what class it is actually deserializing? 换句话说,GenericRequestDeserializer可以找出它实际反序列化的类吗?
So I found a much better option for changing all my objects to snake case. 因此,我找到了一个更好的选择,将所有对象更改为蛇形盒。 Instead of using Serializers and Deserializers on each class, I was able to inject an ObjectMapper into the JsonProvider in Spring. 不必在每个类上使用序列化器和反序列化器,而是可以在Spring中将ObjectMapper注入JsonProvider中。 ObjectMapper already supports a property that will do the camel-case to snake-case automagically. ObjectMapper已经支持一个属性,该属性可以自动将骆驼壳变成蛇形壳。 I just needed to overwrite the getSingletons method in my class that extends Application like so: 我只需要在扩展Application的类中覆盖getSingletons方法,如下所示:
public class MyApp extends Application {
....
@Override
public Set<Object> getSingletons() {
final Set<Object> objects = new LinkedHashSet<Object>();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setPropertyNamingStrategy(
PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objects.add(new JacksonJsonProvider(objectMapper));
return objects;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.