JsonMappingException: no suitable constructor found for type - for external object

I have an object called GeoJsonPoint from the spring framework and it cannot be deserialized using jsonson mapper in my integration test. Also, I cannot add a dummy constructor because it is an external object. So I'm stuck. This is my main essence

 @Document(collection = "foodTrucks") @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY) public class FoodTruckEntity { @Id private ObjectId id; private String applicant; private Status status; private String[] foodItems; private Double longitude; private Double latitude; private GeoJsonPoint geoJsonPoint; public FoodTruckEntity() {}; // getters and setters } 

And test

 @Test public void test() { ClientConfig clientConfig = new DefaultClientConfig(); clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE); Client client = Client.create(clientConfig); String getNearFoodTrucksUrl = "http://localhost:8080/food-truck/near-locations/longitude/-122.398658184604/latitude/37.7901490737255/findAll"; WebResource webResource = client.resource(getNearFoodTrucksUrl); ClientResponse response = webResource.get(ClientResponse.class); GeoResults<FoodTruckEntity> geoResults = webResource.get(new GenericType<GeoResults<FoodTruckEntity>>(){}); if (response.getStatus() != 200) { throw new WebApplicationException(); } } 

And the error I get;

 com.sun.jersey.api.client.ClientHandlerException: org.codehaus.jackson.map.JsonMappingException: No suitable constructor found for type [simple type, class org.springframework.data.geo.GeoResults<entity.FoodTruckEntity>]: can not instantiate from JSON object (need to add/enable type information?) at [Source: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@107e d6fc; line: 1, column: 2] at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:644) at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:604) 

EDIT: This is a knitwear addiction. I AM

 <!-- JERSEY JSON --> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-client</artifactId> <version>1.18.1</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-json</artifactId> <version>1.18.1</version> </dependency> <!-- JERSEY JSON --> 

EDIT_2: the answer as a string is as follows:

 { "averageDistance":{ "value":0.0, "metric":"MILES", "normalizedValue":0.0, "unit":"mi" }, "content":[ { "content":{ "id":{ "timestamp":1429498845, "machineIdentifier":11487078, "processIdentifier":1432, "counter":9275496, "time":1429498845000, "date":1429498845000, "timeSecond":1429498845 }, "applicant":"Cupkates Bakery, LLC", "facilityType":"Truck", "status":"APPROVED", "foodItems":[ "Cupcakes" ], "longitude":-122.398658184604, "latitude":37.7901490737255, "geoJsonPoint":{ "x":-122.398658184604, "y":37.7901490737255, "type":"Point", "coordinates":[ -122.398658184604, 37.7901490737255 ] } }, "distance":{ "value":0.0, "metric":"MILES", "normalizedValue":0.0, "unit":"mi" } } ] } 
+6
source share
1 answer

So, if you look at all the classes from org.springframework.data.geo , you will notice that almost all classes do not have a no-arg constructor, which by default for ObjectMapper should deserialize the POJO from JSON.

One way around this with third-party APIs is to use Jackson Mixins . If you look at GeoModule , this is a module that you can register with ObjectMapper , which includes some Mixins

 mapper.registerModule(new GeoModule()); 

If you look at org.springframework.data.mongodb.core.geo , you get another GeoJsonModule module, which also has Mixins. This module should take care of GeoJsonPoint .

But the main problem for your use case is (if you look at the GeoModule ), then there is no Mixin for GeoResult or GeoResults that you need to parse JSON on.

I created a module for servicing GeoResult , but GeoResults not working at the moment.

 public class GeoModuleExt extends SimpleModule { public GeoModuleExt() { super("Mixins", new Version(1, 0, 0, null)); setMixInAnnotation(GeoResult.class, GeoResultMixin.class); setMixInAnnotation(GeoResults.class, GeoResultsMixin.class); } static abstract class GeoResultMixin { GeoResultMixin(@JsonProperty("content") Object content, @JsonProperty("distance") Distance distance) { } } static abstract class GeoResultsMixin { GeoResultsMixin(@JsonProperty("results")List<GeoResult> results) { } } } 

You can play with him. I don’t have time to work on it (hence the half - @ $$ solution), but when I get some time, if you do not understand this, I will see what I can do.

As a test, you can use ObjectMapper offline to make sure that it works first

 public class Test { public static void main(String[] args) throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new GeoJsonModule()); mapper.registerModule(new GeoModule()); // Our custom module mapper.registerModule(new GeoModuleExt()); // Create FoodTruckEntity - GeoJsonPoint geoJsonPoint = new GeoJsonPoint(10, 10); FoodTruckEntity foodTruck = new FoodTruckEntity(); // set all properties fro foodTruck // Create GeoResult GeoResult<FoodTruckEntity> geoResult = new GeoResult<FoodTruckEntity>(foodTruck, new Distance(10, Metrics.KILOMETERS)); // Serialize geoResult String geoResultString = mapper.writeValueAsString(geoResult); System.out.println(geoResultString); JavaType type = mapper.getTypeFactory().constructParametricType( GeoResult.class, FoodTruckEntity.class); // Deserialize geoResultString GeoResult<FoodTruckEntity> parsedGeoResult = mapper.readValue(geoResultString, type); System.out.println(parsedGeoResult.getDistance()); System.out.println(parsedGeoResult.getContent().getApplicant()); // Up to this point everything is fine. It the deserialization of // `GeoResults` thats a problem. /* List<GeoResult> results = new ArrayList<GeoResult>(); results.add(geoResult); results.add(geoResult); GeoResults geoResults = new GeoResults(results); String resultsString = mapper.writeValueAsString(geoResults); System.out.println(resultsString); JavaType resultType = mapper.getTypeFactory().constructParametricType( GeoResults.class, FoodTruckEntity.class); GeoResults<FoodTruckEntity> parsedGeoResults = mapper.readValue(resultsString, resultType); for (GeoResult<FoodTruckEntity> gr: parsedGeoResults) { System.out.println(gr.getContent().getGeoJsonPoint()); }*/ } } 

When you get a test for work, you can register ObjectMapper with Jersey as

 ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new GeoJsonModule()); mapper.registerModule(new GeoModule()); // Our custom module mapper.registerModule(new GeoModuleExt()); ClientConfig config = new DefaultClientConfig(); config.getSingletons().add(new JacksonJsonProvider(mapper)); Client client = Client.create(config); 

UPDATE

So, after some games, I was able to get it to work with this Mixin for GeoResults . Just upgrade above GeoModuleExt

 static abstract class GeoResultsMixin { GeoResultsMixin(@JsonProperty("results") List<GeoResult> results, @JsonProperty("averageDistance") Distance averageDistance) { } @JsonProperty("results") abstract List<GeoResult> getContent(); } 

It works, as expected, using the above test. Not tested with Jersey yet, but if it works with ObjectMapper , this should not be a problem with Jersey if we set up the Jackson provider to use the mapper.

+5
source

Source: https://habr.com/ru/post/985474/


All Articles