使用 jackson 读取 json 时出现空指针异常

Null Pointer Exception while reading json with jackson

本质上,我有一个 json 对象,我想用 jackson 解析它。我试图将我的测试归结为一个简单的 json 对象和一些示例 jackson 解析代码。例如,我有以下阅读模型json:

import java.util.Set;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;

public class HateoasSet<C> {
  private HateoasEmbedded<C> embedded;
  public Set<C> get() {
    return embedded.content;
  }
  @JsonAlias("_embedded")
  private void set(HateoasEmbedded<C> embedded) {
    this.embedded = embedded;
  }
  private static class HateoasEmbedded<C> {
    @JsonIgnore
    private Set<C> content;
    @JsonAnySetter
    public void setContent(String name, Set<C> content) {
      this.content = content;
    }
  }
}

我正在通过以下方式测试解析:

public static void main(String args[]) throws JsonParseException, JsonMappingException, IOException {
    String json = "{\n" + 
        "    \"_embedded\": {\n" + 
        "        \"endpoints\": [\n" + 
        "            {\n" + 
        "                \"createdAt\": \"2020-06-29T17:25:18.000+00:00\",\n" + 
        "                \"updatedAt\": \"2020-06-29T17:25:30.000+00:00\",\n" + 
        "                \"name\": \"Test User\",\n" + 
        "                \"networkId\": \"net2\",\n" + 
        "                \"endpointType\": \"CL\",\n" + 
        "                \"clientType\": null,\n" + 
        "                \"clientVersion\": null,\n" + 
        "                \"source\": \"IMPORT\",\n" + 
        "                \"syncId\": null,\n" + 
        "                \"registrationKey\": \"registrationkey\",\n" + 
        "                \"registrationAttemptsLeft\": 5,\n" + 
        "                \"status\": 300,\n" + 
        "                \"currentState\": 100,\n" + 
        "                \"stateLastUpdated\": \"2020-06-29T17:25:18.000+00:00\",\n" + 
        "                \"endpointProtectionRole\": null,\n" + 
        "                \"haEndpointType\": null,\n" + 
        "                \"o365BreakoutNextHopIp\": null,\n" + 
        "                \"gatewayClusterId\": null,\n" + 
        "                \"clientMfaEnable\": \"NO\",\n" + 
        "                \"ownerIdentityId\": null,\n" + 
        "                \"countryId\": null,\n" + 
        "                \"geoRegionId\": \"geo1\",\n" + 
        "                \"dataCenterId\": \"data1\",\n" + 
        "                \"sessionIdentityId\": null,\n" + 
        "                \"sessionStatus\": 100,\n" + 
        "                \"id\": \"myId\",\n" + 
        "                \"componentId\": \"componentId\",\n" + 
        "                \"_links\": {\n" + 
        "                    \"self\": {\n" + 
        "                        \"href\": \"www.google.com\"\n" + 
        "                    },\n" + 
        "                    \"network\": {\n" + 
        "                        \"href\": \"www.google.com\"\n" + 
        "                    },\n" + 
        "                    \"appWans\": {\n" + 
        "                        \"href\": \"www.google.com\"\n" + 
        "                    },\n" + 
        "                    \"services\": {\n" + 
        "                        \"href\": \"www.google.com\"\n" + 
        "                    },\n" + 
        "                    \"endpointGroups\": {\n" + 
        "                        \"href\": \"www.google.com\"\n" + 
        "                    },\n" + 
        "                    \"geoRegion\": {\n" + 
        "                        \"href\": \"www.google.com\"\n" + 
        "                    },\n" + 
        "                    \"dataCenter\": {\n" + 
        "                        \"href\": \"www.google.com\"\n" + 
        "                    }\n" + 
        "                }\n" + 
        "            }\n" + 
        "        ]\n" + 
        "    },\n" + 
        "    \"_links\": {\n" + 
        "        \"first\": {\n" + 
        "            \"href\": \"www.google.com\"\n" + 
        "        },\n" + 
        "        \"last\": {\n" + 
        "            \"href\": \"www.google.com\"\n" + 
        "        }\n" + 
        "    },\n" + 
        "    \"page\": {\n" + 
        "        \"size\": 2000,\n" + 
        "        \"totalElements\": 1,\n" + 
        "        \"totalPages\": 1,\n" + 
        "        \"number\": 1\n" + 
        "    }\n" + 
        "}";
    ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    
    HateoasSet<Endpoint> result = mapper.readValue(json, HateoasSet.class);
    System.out.println(result.get());
    
  }

HateoasSet 与 main 方法在同一个包中。有人能告诉我为什么我在尝试解析这个 json 时总是收到空指针异常吗?

我可以通过将 class 更改为

来解决这个问题

public class HateoasSet<C> {
  private HateoasEmbedded<C> embedded;
  public Set<C> get() {
    return embedded.content;
  }
  @JsonAlias("_embedded")
  private void setEmbedded(HateoasEmbedded<C> embedded) {
    this.embedded = embedded;
  }
  private static class HateoasEmbedded<C> {
    @JsonIgnore
    private Set<C> content;
    @JsonAnySetter
    public void setContent(String name, Set<C> content) {
      this.content = content;
    }
  }
}

测试部分:

public static void main(String args[]) throws JsonParseException, JsonMappingException, IOException {
    String json = "{\n" + 
        "    \"_embedded\": {\n" + 
        "        \"endpoints\": [\n" + 
        "            {\n" + 
        "                \"createdAt\": \"2020-06-29T17:25:18.000+00:00\",\n" + 
        "                \"updatedAt\": \"2020-06-29T17:25:30.000+00:00\",\n" + 
        "                \"name\": \"Test User\",\n" + 
        "                \"networkId\": \"net2\",\n" + 
        "                \"endpointType\": \"CL\",\n" + 
        "                \"clientType\": null,\n" + 
        "                \"clientVersion\": null,\n" + 
        "                \"source\": \"IMPORT\",\n" + 
        "                \"syncId\": null,\n" + 
        "                \"registrationKey\": \"registrationkey\",\n" + 
        "                \"registrationAttemptsLeft\": 5,\n" + 
        "                \"status\": 300,\n" + 
        "                \"currentState\": 100,\n" + 
        "                \"stateLastUpdated\": \"2020-06-29T17:25:18.000+00:00\",\n" + 
        "                \"endpointProtectionRole\": null,\n" + 
        "                \"haEndpointType\": null,\n" + 
        "                \"o365BreakoutNextHopIp\": null,\n" + 
        "                \"gatewayClusterId\": null,\n" + 
        "                \"clientMfaEnable\": \"NO\",\n" + 
        "                \"ownerIdentityId\": null,\n" + 
        "                \"countryId\": null,\n" + 
        "                \"geoRegionId\": \"geo1\",\n" + 
        "                \"dataCenterId\": \"data1\",\n" + 
        "                \"sessionIdentityId\": null,\n" + 
        "                \"sessionStatus\": 100,\n" + 
        "                \"id\": \"myId\",\n" + 
        "                \"componentId\": \"componentId\",\n" + 
        "                \"_links\": {\n" + 
        "                    \"self\": {\n" + 
        "                        \"href\": \"www.google.com\"\n" + 
        "                    },\n" + 
        "                    \"network\": {\n" + 
        "                        \"href\": \"www.google.com\"\n" + 
        "                    },\n" + 
        "                    \"appWans\": {\n" + 
        "                        \"href\": \"www.google.com\"\n" + 
        "                    },\n" + 
        "                    \"services\": {\n" + 
        "                        \"href\": \"www.google.com\"\n" + 
        "                    },\n" + 
        "                    \"endpointGroups\": {\n" + 
        "                        \"href\": \"www.google.com\"\n" + 
        "                    },\n" + 
        "                    \"geoRegion\": {\n" + 
        "                        \"href\": \"www.google.com\"\n" + 
        "                    },\n" + 
        "                    \"dataCenter\": {\n" + 
        "                        \"href\": \"www.google.com\"\n" + 
        "                    }\n" + 
        "                }\n" + 
        "            }\n" + 
        "        ]\n" + 
        "    },\n" + 
        "    \"_links\": {\n" + 
        "        \"first\": {\n" + 
        "            \"href\": \"www.google.com\"\n" + 
        "        },\n" + 
        "        \"last\": {\n" + 
        "            \"href\": \"www.google.com\"\n" + 
        "        }\n" + 
        "    },\n" + 
        "    \"page\": {\n" + 
        "        \"size\": 2000,\n" + 
        "        \"totalElements\": 1,\n" + 
        "        \"totalPages\": 1,\n" + 
        "        \"number\": 1\n" + 
        "    }\n" + 
        "}";
    ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    
    HateoasSet<EndpointGroup> result = mapper.readValue(json, new TypeReference<HateoasSet<EndpointGroup>>(){});
    System.out.println(result.get());
    
  }