杰克逊将GeoJsonPoint序列化为纬度/经度

时间:2018-10-21 12:13:41

标签: java jackson

我有一个类似于此类的帖子:

@Document(collection = "Posts")
@Data
public class Post {

    @Id
    private ObjectId _id;
    @NonNull private String userId;
    @NonNull private String firstName;
    @NonNull private String lastName;
    private String postText;
    private String postImageUri;
    @NonNull private String googlePlaceId;
    @NonNull private String googlePlaceName;
    @NonNull private GeoJsonPoint location;

    @JsonCreator
    public Post(@JsonProperty("userId") String userId,
                @JsonProperty("firstName")String firstName,
                @JsonProperty("lastName")String lastName,
                @JsonProperty("postText") String postText,
                @JsonProperty("postImageUri") String postImageUri,
                @JsonProperty("googlePlaceId") String googlePlaceId,
                @JsonProperty("googlePlaceName") String googlePlaceName,
                @JsonProperty("latitude") long latitude,
                @JsonProperty("longitude") long longitude) {
        this.userId = userId;
        this.firstName = firstName;
        this.lastName = lastName;
        this.postText = postText;
        this.postImageUri = postImageUri;
        this.googlePlaceId = googlePlaceId;
        this.googlePlaceName = googlePlaceName;
        this.location = new GeoJsonPoint(longitude, latitude);
    }

}

Mongo-reactive-driver使用该类存储在Mongo数据库中。 GeoJsonPoint是一种特殊的存储类型,因此我不想单独存储纬度和经度字段。

基本上,我的代码运行良好。使用Spring Boot:

@PostMapping("")
public Mono<ResponseEntity<Post>> savePost(@RequestBody final Post post) {
    // Fire and forgat
    ablyService.publishPost(post.getGooglePlaceId(), post);
    return postRepo.save(post)
            .map(savedPost -> new ResponseEntity<>(savedPost, HttpStatus.CREATED));
}

我的问题是当我编写集成测试时。我想做什么:

@Test
public void createPostTest() {
    Post post = new Post("someUserId", "Kim", "Gysen",
            "Some text", "http://zwoop.be/imagenr",
            "googlePlaceId", "googlePlaceName", 50, 50);

    webTestClient.post().uri(BASE_URI)
            .contentType(MediaType.APPLICATION_JSON_UTF8)
            .accept(MediaType.APPLICATION_JSON_UTF8)
            .body(Mono.just(post), Post.class)
            .exchange()
            .expectStatus().isCreated()
            .expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)
            .expectBody()
            .jsonPath("$._id").isNotEmpty()
            .jsonPath("$.userId").isEqualTo(post.getUserId())
            .jsonPath("$.firstName").isEqualTo(post.getFirstName())
            .jsonPath("$.lastName").isEqualTo(post.getLastName())
            .jsonPath("$.postText").isEqualTo(post.getPostText())
            .jsonPath("$.postImageUri").isEqualTo(post.getPostImageUri())
            .jsonPath("$.location.x").isEqualTo(post.getLocation().getX())
            .jsonPath("$.location.y").isEqualTo(post.getLocation().getY());
}

我得到的错误是:

  

org.springframework.core.codec.CodecException:类型定义错误:   [简单类型,类   org.springframework.data.mongodb.core.geo.GeoJsonPoint];嵌套的   例外是   com.fasterxml.jackson.databind.exc.InvalidDefinitionException:无法   构造的实例   org.springframework.data.mongodb.core.geo.GeoJsonPoint(没有创造者,   像默认构造一样,存在):无法从Object值反序列化   (没有基于委托人或财产的创建者)

我想要的是在测试中使用“纬度”和“经度” json字段序列化对象,同时保持其余实现逻辑按原样工作。这该怎么做?

1 个答案:

答案 0 :(得分:0)

哦,很好。只需通过更改api来接受自定义“位置”字段并编写杰克逊序列化器即可解决此问题:

@Document(collection = "Posts")
@Data
public class Post {

    @Id
    private ObjectId _id;
    @NonNull private String userId;
    @NonNull private String firstName;
    @NonNull private String lastName;
    private String postText;
    private String postImageUri;
    @NonNull private String googlePlaceId;
    @NonNull private String googlePlaceName;
    @JsonSerialize(using = LocationToLatLngSerializer.class)
    @NonNull private GeoJsonPoint location;

    @JsonCreator
    public Post(@JsonProperty("userId") String userId,
                @JsonProperty("firstName")String firstName,
                @JsonProperty("lastName")String lastName,
                @JsonProperty("postText") String postText,
                @JsonProperty("postImageUri") String postImageUri,
                @JsonProperty("googlePlaceId") String googlePlaceId,
                @JsonProperty("googlePlaceName") String googlePlaceName,
                @JsonProperty("location") Geolocation location) {
        this.userId = userId;
        this.firstName = firstName;
        this.lastName = lastName;
        this.postText = postText;
        this.postImageUri = postImageUri;
        this.googlePlaceId = googlePlaceId;
        this.googlePlaceName = googlePlaceName;
        this.location = new GeoJsonPoint(location.getLongitude(), location.getLatitude());
    }

    static class LocationToLatLngSerializer extends JsonSerializer<GeoJsonPoint> {

        @Override
        public void serialize(GeoJsonPoint value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            gen.writeStartObject();
            gen.writeNumberField("latitude", value.getX());
            gen.writeNumberField("longitude", value.getY());
            gen.writeEndObject();
        }
    }
}