我有以下JSON,其中包含从用户ID到用户详细信息的映射:
{
"users": {
"john": { "firstName": "John", "lastName": "Doe" },
"mark": { "firstName": "Mark", "lastName": "Smith" }
}
}
我正在使用以下代码将JSON反序列化为Java对象:
class User {
public String userID;
public String firstName;
public String lastName;
}
public class Users {
public Map<String, User> users;
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
Reader source = Files.newBufferedReader(Paths.get("test.json"));
Users all = mapper.readValue(source, Users.class);
// ...
}
}
反序列化后,我希望将字段User.userID
设置为users
地图中的相应密钥。
例如all.users.get("john").userID
应为"john"
。
我该怎么做?
答案 0 :(得分:1)
为User对象创建自定义反序列化器并将其用于Map。这是一个完整的例子:
@Test
public void test() throws JsonParseException, JsonMappingException, IOException {
ObjectMapper mapper = new ObjectMapper();
Data data = mapper.readValue("{\"users\": {\"John\": {\"id\": 20}, \"Pete\": {\"id\": 30}}}", Data.class);
assertEquals(20, data.users.get("John").id);
assertEquals(30, data.users.get("Pete").id);
assertEquals("John", data.users.get("John").name);
assertEquals("Pete", data.users.get("Pete").name);
}
public static class Data {
@JsonDeserialize(contentUsing = Deser.class)
public Map<String, User> users;
}
public static class User {
public String name;
public int id;
}
public static class Deser extends JsonDeserializer<User> {
@Override
public User deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
String name = ctxt.getParser().getCurrentName();
User user = p.readValueAs(User.class);
user.name = name; // This copies the key name to the user object
return user;
}
}
答案 1 :(得分:0)
最简单的解决方法是为需要映射键的类实现自定义反序列化器(请参见john16384's answer)。但是,如果您的JSON中有多个具有不同值类型的映射,这将很麻烦,因为每种类型都需要一个反序列化器。
在这种情况下,有一个更好的解决方案:我将创建一个自定义@JsonMapKey
注释来标记映射键的目标属性,然后注册一个通用的自定义反序列化器,以处理所有出现的注释。这些是您需要的部分:
自定义@JsonMapKey
注释:
/**
* Annotation used to indicate that the annotated property shall be deserialized to the map key of
* the current object. Requires that the object is a deserialized map value.
*
* Note: This annotation is not a standard Jackson annotation. It will only work if this is
* explicitly enabled in the {@link ObjectMapper}.
*/
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface JsonMapKey {
}
处理@JsonMapKey
批注的自定义反序列化器:
public class JsonMapKeyDeserializer extends DelegatingDeserializer {
private static final long serialVersionUID = 1L;
private BeanDescription beanDescription;
public JsonMapKeyDeserializer(JsonDeserializer<?> delegate, BeanDescription beanDescription) {
super(delegate);
this.beanDescription = beanDescription;
}
@Override
protected JsonDeserializer<?> newDelegatingInstance(JsonDeserializer<?> newDelegatee) {
return new JsonMapKeyDeserializer(newDelegatee, beanDescription);
}
@Override
public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String mapKey = p.getCurrentName();
Object deserializedObject = super.deserialize(p, ctxt);
// set map key on all fields annotated with @JsonMapKey
for (BeanPropertyDefinition beanProperty : beanDescription.findProperties()) {
AnnotatedField field = beanProperty.getField();
if (field != null && field.getAnnotation(JsonMapKey.class) != null) {
field.setValue(deserializedObject, mapKey);
}
}
return deserializedObject;
}
}
在ObjectMapper
中注册自定义反序列化器:
private static void registerJsonMapKeyAnnotation(ObjectMapper objectMapper) {
SimpleModule module = new SimpleModule();
module.setDeserializerModifier(new BeanDeserializerModifier() {
@Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config,
BeanDescription beanDescription, JsonDeserializer<?> originalDeserializer) {
return new JsonMapKeyDeserializer(originalDeserializer, beanDescription);
}
});
objectMapper.registerModule(module);
}
然后,您只需注释要用于地图键的字段...
class User {
@JsonMapKey
public String userID;
public String firstName;
public String lastName;
}
...并使用准备好的ObjectMapper
反序列化JSON:
Users all = registerJsonMapKeyAnnotation(new ObjectMapper()).readValue(source, Users.class);
答案 2 :(得分:-1)
首先创建ObjectMapper
class
对象,而不是configure
。
尝试以下一个。
示例代码
Map<K, V> map;
ObjectMapper mapper = new ObjectMapper();
mapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
map = mapper.readValue(jsonStr, new TypeReference<Map<K, V>>() {});
可以使用Map
获取值。