Jackson JSON映射到具有树遍历的对象

时间:2014-06-19 13:45:13

标签: java json mapping jackson resttemplate

我有以下JSON,我想将其映射到一个对象。

{
    "response": {
        "original": {
            "status": {
                "code": "SUCCESS"
            },
            "organisationNode": [
                {
                    "organisationId": {
                        "identifier": "2005286047",
                        "identifierType": "BECBE"
                    },
                    "organisationLevel": "Subdivision",
                    "organisationCode": "ENT_CBE",
                    "organisationParentNode": {
                        "organisationId": {
                            "identifier": "0878016185",
                            "identifierType": "BEEUN"
                        },
                        "organisationLevel": "Entity",
                        "organisationCode": "ENT_CBE"
                    }
                }
            ]
        }
    }
}

我希望我的Java Object看起来像这样:

public class Structure {

  private String status;  //SUCCESS

  private List<OrganisationNode> organisationNodes;

  public class OrganisationNode {
    private String organisationId;  //2005286047
    private String organisationLevel; //Subdivision

    private List<OrganisationNode> organisationNodes;
  }
}

有没有某种杰克逊注释可以看到例如:

@SomeAnnotation("response.original.status.code")
private String status;

我正在使用restTemplate调用JSON服务(它为我提供上面的JSON响应):

ResponseEntity<Structure> response = restTemplate.postForEntity(endpoint, requestObject, Structure.class);

2 个答案:

答案 0 :(得分:1)

没有Jackson注释将对象字段映射到树中的Json节点,但实现起来并不困难。以下是需要完成的3个方面:

  1. 使用路径值创建自定义注释。
  2. 创建一个自定义反序列化器,根据注释的路径值定位节点并将其转换为字符串。
  3. 注册一个annotation introspector,它会告诉Jackson注释了注释的字段或参数被映射到json属性,并且应该使用你的反序列化器。
  4. 以下是完整的示例:

    public class JacksonContextualSerializer {
    
        @Retention(RetentionPolicy.RUNTIME)
        public static @interface SomeAnnotation {
            String value();
        }
    
        public static final String JSON = "{\n" +
                "    \"response\": {\n" +
                "        \"original\": {\n" +
                "            \"status\": {\n" +
                "                \"code\": \"SUCCESS\"\n" +
                "            }\n" +
                "       }\n" +
                "    }\n" +
                "}";
    
        public static class PathAwareSerializer extends JsonDeserializer<String>
                implements ContextualDeserializer {
            private String path;
    
            @Override
            public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
                                                        BeanProperty property)
                    throws JsonMappingException {
                // when the serializer implements the ContextualDeserializer, then we have
                // the access to the element's annotation value
                path = property.getMember().getAnnotation(SomeAnnotation.class).value();
                return this;
            }
    
            @Override
            public String deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
                // read JSON as tree
                JsonNode node = jp.readValueAs(JsonNode.class);
                // find the last node starting from the second path element, since the first
                // is covered by the property name (see the introspector)
                String[] pathArray = path.split("\\.");
                for (int i = 1; i < pathArray.length; i++) {
                    node = node.get(pathArray[i]);
                }
                return node.asText();
            }
        }
    
        public static class Bean {
            private final String status;
    
            @JsonCreator
            public Bean(@SomeAnnotation("response.original.status.code") String status) {
                this.status = status;
            }
    
            @Override
            public String toString() {
                return "Bean{" +
                        "status='" + status + '\'' +
                        '}';
            }
        }
    
        public static void main(String[] args) throws IOException {
            ObjectMapper mapper = new ObjectMapper();
            // register an introspector which will inject jackson annotations to elements that are
            // marked by the custom annotation.
            mapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector() {
                @Override
                public PropertyName findNameForDeserialization(Annotated a) {
                    if (a.hasAnnotation(SomeAnnotation.class)) {
                        // if annotation is present then this is a property which name is the first
                        // element in the path
                        String path = a.getAnnotation(SomeAnnotation.class).value();
                        return new PropertyName(path.split("\\.")[0]);
                    }
                    return super.findNameForDeserialization(a);
                }
    
                @Override
                public Class<? extends JsonDeserializer<?>> findDeserializer(Annotated a) {
                    // if the annotation is present, then the property is deserialized using
                    // the custom serializer
                    if (a.hasAnnotation(SomeAnnotation.class)) {
                        return PathAwareSerializer.class;
                    }
                    return super.findDeserializer(a);
                }
            });
    
            System.out.println(mapper.readValue(JSON, Bean.class));
        }
    }
    

    输出:

    Bean{status='SUCCESS'}
    

答案 1 :(得分:0)

Spring Documentation表示如果你的pom.xml中有这种依赖关系并且你的spring上下文中有标记<mvc:annotation-driven>,那么Spring MVC会自动为你的REST模板注册一个JSON转换器

<dependency>
   <groupId>org.codehaus.jackson</groupId>
   <artifactId>jackson-mapper-asl</artifactId>
   <version>1.9.3</version>
</dependency>

您的JSON字符串和Java对象中存在一些不一致之处。 例如。 Status也应该是具有字段代码而不是字符串

的类型