我正在尝试使用 RESTTemplate api 编写以下 JSON 格式的 POJO 类,但我无法使用 Map 解析所需的 json 格式。 我应该使用什么属性类型来获取低于 json 格式的属性?请给我建议。
@JsonProperty("ID")
private String id = null;
@JsonProperty("NAME")
private String name = null;
@JsonProperty("AGE")
private int age = 0;
@JsonProperty("HOBBIES")
private Map<String, String> hobbies = null;
生成的 JSON 格式:
{"NAME":"Shas","ID":"1","AGE":29,"HOBBIES":{"HOBBIES[1]":"Chess","HOBBIES[0]":"Cricket"}}
预期格式:
{"NAME":"Shas","ID":"1","AGE":29,"HOBBIES[0]":"Cricket", "HOBBIES[1]":"Chess"}
最佳答案
无论如何,你都需要编写一个序列化程序,这是一个通用序列化程序,它将序列化所有归档到“HOBBIES[0]
这种形式的Map。
@Test
public void test() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(new POJO().setHobbies(ImmutableMap.of("0", "Cricket", "1", "Chess")));
System.out.println(json);
}
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MapAsField {
}
@Data
@Accessors(chain = true)
@JsonSerialize(using = CustomJsonSerializer.class)
public static class POJO {
@JsonProperty("ID")
private String id = "abc";
@JsonProperty("NAME")
private String name = "wener";
@JsonProperty("AGE")
private int age = 0;
@JsonProperty("HOBBIES")
@MapAsField
private Map<String, String> hobbies = null;
private Map<String, String> fav = ImmutableMap.of("A", "Yes", "B", "No");
}
static class CustomJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeStartObject();
JavaType javaType = provider.constructType(Object.class);
BeanDescription beanDesc = provider.getConfig().introspect(javaType);
ListIterator<BeanPropertyDefinition> itor = beanDesc.findProperties()
.listIterator();
// Remove map field
ArrayList<BeanPropertyDefinition> list = new ArrayList<>();
while (itor.hasNext()) {
BeanPropertyDefinition n = itor.next();
if (n.getField().getAnnotated().getAnnotation(MapAsField.class) != null && // Only handle this
Map.class.isAssignableFrom(n.getField().getRawType())) {
itor.remove();
list.add(n);
}
}
JsonSerializer<Object> serializer = BeanSerializerFactory
.instance
.findBeanSerializer(provider, javaType, beanDesc);
serializer.unwrappingSerializer(null).serialize(value, gen, provider);
// Handle all map field
for (BeanPropertyDefinition d : list) {
try {
Field field = d.getField().getAnnotated();
field.setAccessible(true);
Map<?, ?> v = (Map<?, ?>) field.get(value);
if (v != null && !v.isEmpty()) {
for (Map.Entry o : v.entrySet()) {
gen.writeStringField(
String.format("%s[%s]", d.getName(), o.getKey().toString()),
o.getValue().toString()
);
}
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
gen.writeEndObject();
}
}
输出
{"fav":{"A":"Yes","B":"No"},"ID":"abc","NAME":"wener","AGE":0,"HOBBIES[0]":"Cricket","HOBBIES[1]":"Chess"}
更新
如果你有很多bean需要这个功能,添加序列化器注释很烦人,所以,你可以把这个序列化器写成修饰符。
@Test
public void test2() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new SimpleModule().setSerializerModifier(new MapAsFieldModifier()));
System.out.println(mapper.writeValueAsString(new POJO2()));
}
@Data
@Accessors(chain = true)
public static class POJO2 {
@JsonProperty("ID")
private String id = "abc";
@JsonProperty("NAME")
private String name = "wener";
@JsonProperty("AGE")
private int age = 0;
@JsonProperty("HOBBIES")
@MapAsField
private Map<String, String> hobbies = ImmutableMap.of("0", "Cricket", "1", "Chess");
private Map<String, String> fav = ImmutableMap.of("A", "Yes", "B", "No");
}
public class MapAsFieldModifier extends BeanSerializerModifier {
@Override
public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc,
JsonSerializer<?> serializer) {
ListIterator<BeanPropertyDefinition> itor = beanDesc.findProperties().listIterator();
// Remove map field
ArrayList<BeanPropertyDefinition> list = new ArrayList<>();
while (itor.hasNext()) {
BeanPropertyDefinition n = itor.next();
if (n.getField().getAnnotated().getAnnotation(MapAsField.class) != null && // Only handle this
Map.class.isAssignableFrom(n.getField().getRawType())) {
itor.remove();
list.add(n);
}
}
// We should handle this
if (!list.isEmpty()) {
return new JsonSerializer<Object>() {
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers)
throws IOException, JsonProcessingException {
gen.writeStartObject();
JavaType javaType = serializers.constructType(value.getClass());
JsonSerializer<Object> ser = BeanSerializerFactory
.instance
.findBeanSerializer(serializers, javaType, beanDesc);
ser.unwrappingSerializer(null).serialize(value, gen, serializers);
// Handle all map field
for (BeanPropertyDefinition d : list) {
try {
Field field = d.getField().getAnnotated();
field.setAccessible(true);
Map<?, ?> v = (Map<?, ?>) field.get(value);
if (v != null && !v.isEmpty()) {
for (Map.Entry o : v.entrySet()) {
gen.writeStringField(
String.format("%s[%s]", d.getName(), o.getKey().toString()),
o.getValue().toString()
);
}
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
gen.writeEndObject();
}
};
}
return serializer;
}
}
输出
{"fav":{"A":"Yes","B":"No"},"ID":"abc","NAME":"wener","AGE":0,"HOBBIES[0]":"Cricket","HOBBIES[1]":"Chess"}
关于java - Jackson JSON 动态键值绑定(bind)到 Java Bean,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43627905/