Cannot parse Google geocode json object via webclient - java

I try to call following webclient query:
return webClient
.get()
.uri(uriBuilder -> uriBuilder
.path("/geocode/json")
.queryParam("key", google.getApiKey())
.queryParam("latlng", String.join(
",",
String.valueOf(point.getLat()),
String.valueOf(point.getLng()))
)
.build())
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.onStatus(HttpStatus::isError, RestErrorHandler::manageError)
.bodyToMono(*PlacesSearchResponse.class*);
REST operation from google returns (https://developers.google.com/maps/documentation/geocoding/overview#GeocodingResponses) following object:
{
"results" : [
{
"address_components" : [
{
"long_name" : "1600",
"short_name" : "1600",
"types" : [ "street_number" ]
}
],
"formatted_address" : "1600 Amphitheatre Parkway, Mountain View, CA 94043, USA",
"geometry" : {
"location" : {
"lat" : 37.4224764,
"lng" : -122.0842499
},
"location_type" : "ROOFTOP",
"viewport" : {
"northeast" : {
"lat" : 37.4238253802915,
"lng" : -122.0829009197085
},
"southwest" : {
"lat" : 37.4211274197085,
"lng" : -122.0855988802915
}
}
},
"place_id" : "ChIJ2eUgeAK6j4ARbn5u_wAGqWA",
"plus_code": {
"compound_code": "CWC8+W5 Mountain View, California, United States",
"global_code": "849VCWC8+W5"
},
"types" : [ "street_address" ]
}
],
"status" : "OK"
}
And problem is that I cannot parse it into my class: PlacesSearchResponse.class
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public class PlacesSearchResponse {
public String status;
public String errorMessage;
#JsonProperty(value = "results")
public List<PlacesSearchResult> results;
}
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public class PlacesSearchResult implements Serializable{
private static final long serialVersionUID = 1L;
#JsonProperty(value = "address_components")
public AddressComponent addressComponents[];
}
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public class AddressComponent implements Serializable {
private static final long serialVersionUID = 1L;
public String longName;
public String shortName;
#JsonProperty(value = "types")
public String[] types;
}
I cannot find any mistake and webclient is ok, because when I tried bodyToMono(String.class) then I saw this object correctly.

I think you should parse it into an array, so do the following:
...
.bodyToMono(PlacesSearchResponse[].class);

Finnaly I have following call with objects:
.bodyToMono(PlacesSearchResponse.class);
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public class PlacesSearchResponse {
public String status;
public String errorMessage;
List <PlacesSearchResult> results;
}
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public class PlacesSearchResult implements Serializable{
#JsonProperty("place_id")
String placeId;
#JsonProperty("address_components")
List<AddressComponent> addressComponents;
#JsonProperty("formatted_address")
String formattedAddress;

Related

How to filter in mongo repository for array of objects

Here i'm using MongoRepository and i need to query a list of objects that includes certain id in an array of objects inside.
The document structure :
{
"_id" : ObjectId("5ccc1c54a3d5eed9a6b8015a"),
"email" : "sineth3#gmail.com",
"name" : "edward3",
"businessName" : "aroma3",
"phone" : "07177222233",
"address" : "no 100 NY",
"bookletSignups" : [
{
"bookletId" : "sample-booklet",
"contactName" : "john doe"
},
{
"bookletId" : "sample-booklet1",
"contactName" : "john doe1"
}
],
"eventSignups" : [
{
"eventId" : "sample-event",
"contactName" : "john doe2"
},
{
"eventId" : "sample-event 1",
"contactName" : "john doe3"
}
],
"infoSignups" : [
{
"infoRequestId" : "sample-info ",
"contactName" : "john doe4"
},
{
"infoRequestId" : "sample-event 1",
"contactName" : "john doe5"
}
],
"webinarSignups" : [
{
"webinarId" : "sample-webinar ",
"contactName" : "john doe6"
},
{
"webinarId" : "sample-webinar 1",
"contactName" : "john doe7"
}
],
"updatedTime" : ISODate("2016-03-03T08:00:00Z")
}
The Repository :
#Repository
public interface UserRepository extends MongoRepository<User,String> {
#org.springframework.data.mongodb.repository.Query(value = "{ 'bookletSignups': { $elemMatch: { 'bookletSignups.bookletId' : ?0 } }}")
List<User> findByBookletId(String id);
}
User model class:
#Id
private String id;
private String email;
private String name;
private String businessName;
private String phone;
private String address;
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private Date createdTime;
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private Date updatedTime;
#Field("bookletSignups")
#DBRef
private List<BookletSignUp> bookletSignups;
#Field("eventSignups")
#DBRef
private List<EventSignUp> eventSignups;
#Field("infoSignups")
#DBRef
private List<InfoSignUp> infoSignups;
#Field("webinarSignups")
#DBRef
private List<WebinarSignUp> webinarSignups;
So im trying to retrieve User objects that includes a bookletSignups object with the passing bookletId value. But the result is empty. What has gone wrong here?
I would say you need to modify your query to looks like this:
#Repository
public interface UserRepository extends MongoRepository<User,String> {
#org.springframework.data.mongodb.repository.Query(value = "{ 'bookletSignups': { $elemMatch: { 'bookletId' : ?0 } }}")
List<User> findByBookletId(String id);
}
If you check MongoDB documentation for $elemMatch, link to documentation, you can see that basically in $elemMatch operator you are using field in embedded object, so you don't need to specify again name of array in which you are searching for objects.

Aggregation lookup not working in spring

I am running the following aggregation lookup query in spring but it doesn't seems to output the same result as one i run in mongo shell. I am guessing mongo shell knows that from:"testModel" collection exists but how do spring know "testModel" exists as we are only pass strings in Aggregation.lookup("testModel"). I can run all other stages fine for example match or project..
// code running in Mongo Shell
db.demoModel.aggregate([{
$lookup:
{
from: "testModel",
localField: "_id",
foreignField: "makeId",
as: "cool"
}
}]
)
// code from spring
public List<DemoModel> getSomeAutos() throws Exception {
LookupOperation lookupStage = Aggregation.lookup(
"testModel",
"_id",
"makeId",
"cool"
);
Aggregation aggregation = Aggregation.newAggregation(lookupStage);
List<DemoModel> demomode = mongoTemplate.aggregate(aggregation, "demoModel", DemoModel.class).getMappedResults();
return demomode;
}
// DemoModel.class
public class DemoModel {
#Id
private String id;
private String value;
private String label;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
}
//Mongo demoModel Collection
{
"_id" : ObjectId("5a8ee0d815dc17aa32f90f4b"),
"value" : "Mitsubishi",
"label" : "Mitsubishi"
}
{
"_id" : ObjectId("5a8ee0d815dc17aa32f90f4c"),
"value" : "BMW",
"label" : "BMW"
}
// Mongo testModel Collection
{
"_id" : ObjectId("5a8ee393b80c346266f25aba"),
"make" : "Mitsubishi",
"label" : "3000GT",
"value" : "3000GT",
"makeId" : ObjectId("5a8ee0d815dc17aa32f90f4b")
}
{
"_id" : ObjectId("5a8ee393b80c346266f25af8"),
"make" : "BMW",
"label" : "Alpina A2",
"value" : "Alpina A2",
"makeId" : ObjectId("5a8ee0d815dc17aa32f90f4c")
}
// Response i am getting
[
{
"id": "5a8ee0d815dc17aa32f90f4b",
"value": "Mitsubishi",
"label": "Mitsubishi"
},
{
"id": "5a8ee0d815dc17aa32f90f4c",
"value": "BMW",
"label": "BMW"
}
]
// expected response in this format
{
"_id" : ObjectId("5a8ee0d815dc17aa32f90f4b"),
"value" : "Mitsubishi",
"label" : "Mitsubishi",
"cool" : [
{
"_id" : ObjectId("5a8ee393b80c346266f25aba"),
"make" : "Mitsubishi",
"label" : "3000GT",
"value" : "3000GT",
"makeId" : ObjectId("5a8ee0d815dc17aa32f90f4b")
}]
}

Jackson Serialize List Entities (add field to root list)

this my entity
#Entity
public class Product extends AbstractBaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Type(type = "objectid")
private String id;
private String title;
my resources
#Path(value = ApiConstant.Urls.PRODUCTS)
public class ProductResource {
#Inject
private ProductService productService;
#GET
#Path(value = ApiConstant.Urls.PRODUCTS)
#Produces(value = MediaType.APPLICATION_JSON)
public List getProducts(){
return productService.findAll();
}
my json response
[ {
"id" : "596b6a02f70a0878590bcf08",
"title" : "test1",
"description" : "description test 1"
}, {
"id" : "596b6b00f70a087b72d377eb",
"title" : "test1",
"description" : "description test 1"
}, {
"id" : "596b6b75f70a087d40f580d5",
"title" : "test1",
"description" : "description test 1"
} ]
I want to create a count field that counts the items in the list
like this and add the list to the results field
{
"count": 3,
"results": [
{
"id" : "596b6a02f70a0878590bcf08",
"title" : "test1",
"description" : "description test 1"
}, {
"id" : "596b6b00f70a087b72d377eb",
"title" : "test1",
"description" : "description test 1"
}, {
"id" : "596b6b75f70a087d40f580d5",
"title" : "test1",
"description" : "description test 1"
} ],
}
I want to serialize the Product List returned by jpa persistence
You can use the following class to include a count along with a list of Product entities:
public class ResultList {
private int count;
#JsonProperty("results") private List<Product> products;
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = Objects.requireNonNull(products, "products");
this.count = products.size();
}
public int getCount() {
return count;
}
}
Class with generics type
public class ResultList<T> {
private int count;
#JsonProperty("results")
private List<T> items;
public List<T> getItems() {
return items;
}
public void setItems(List<T> items) {
this.items = Objects.requireNonNull(items, "items");
this.count = items.size();
}
public int getCount() {
return count;
}
}
ProductResource
#GET
#Path(value = ApiConstant.Urls.PRODUCTS)
#Produces(value = MediaType.APPLICATION_JSON)
public ResultList getProducts(){
List products = productService.findAll();
ResultList result = new ResultList<Product>();
result.setItems(products);
return result;
}
Thanks #ck1

Convert ObjectNode to Java Object using Jackson

I have a json:
{
"response": {
"GeoObjectCollection": {
"featureMember": [
{
"GeoObject": {
"description": "Country",
"name": "City",
"Point": {
"pos": "31.992615 45.057626"
}
}
},
{
"GeoObject": {
"description": "Country",
"name": "City",
"Point": {
"pos": "49.242414 49.895935"
}
}
}
]
}
}
}
I created DTO:
GeographicCoordinateDto.java:
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public class GeographicCoordinateDto {
#JsonProperty("description")
private String location;
#JsonProperty("name")
private String cityName;
#JsonProperty("Point")
private GeographicCoordinatesDto geoCoordinates;
}
GeographicCoordinatesDto.java:
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public class GeographicCoordinatesDto {
#JsonProperty("pos")
private String geoCoordinates;
}
Then I get JsonNode:
List<JsonNode> responseArrayOfObjects = mapper.readValue(new URL(yandexGeoCoderRestUrl+address), ObjectNode.class).findValues("GeoObject");
And I'm trying to convert to my DTO:
GeographicCoordinatesDto geo = mapper.convertValue(responseArrayOfObjects.get(0), GeographicCoordinatesDto.class);
But, I've null object:
GeographicCoordinatesDto(geoCoordinates=null)
What could be wrong?
UPDATE:
responseArrayOfObjects contains:
You are trying to get pos from the GeographicCoordinatesDto object, but it is inside the Point object of GeographicCoordinatesDto.
You can do this instead:
List<JsonNode> responseArrayOfObjects = mapper.readValue(new URL(yandexGeoCoderRestUrl+address), ObjectNode.class).findValues("Point");
or create another class for Point:
#JsonIgnoreProperties(ignoreUnknown = true)
class Point {
#JsonProperty("pos")
private String geoCoordinates;
}
and use it in GeographicCoordinatesDto:
#JsonIgnoreProperties(ignoreUnknown = true)
class GeographicCoordinatesDto {
#JsonProperty("Point")
private Point point;
}

Self-referencing JSON with Spring Data REST

Self-referencing JSON with Spring Data REST
In a Spring Data REST data model with Lombok, how can we export and import data to self-referencing JSON without creating a parallel entities or DTOs?
For example, a self-referencing JSON using JSONPath for a simple music manager might look like:
{ "id" : 1,
"albums" : [ {
"id" : 1,
"title" : "Kind Of Blue",
"artist" : "$..artists[?(#.id=1)]",
"tracks" : [ {
"id" : 1,
"title" : "So What",
"duration" : "PT9M5S",
"musicians" : [ {
"musician" : "$..artists[?(#.id=1)]",
}, {
"musician" : "$..artists[?(#.id=2)]",
} ]
}, {
"id" : 3,
"title" : "Blue in Green",
"duration" : "PT5M29S",
"musicians" : [ {
"musician" : "$..artists[?(#.id=1)]",
}, {
"musician" : "$..artists[?(#.id=2)]",
} ]
} ]
} ],
"artists" : [ {
"id" : 1,
"firstName" : "Miles",
"lastName" : "Davis",
"birthDate" : "1926-05-26"
}, {
"id" : 2,
"firstName" : "Bill",
"lastName" : "Evans",
"birthDate" : "1929-09-16"
} ]
}
How can we create the import and export functionality for this representation while retaining the Spring Data REST HATEOAS functionality? The musicians container in an export/import has an array of string JSONPath expressions and in the REST APIs the musicians is an array of Person objects (see below) -- so how can Jackson be configured to select the correct serializer and deserializer the export and import operations?
Details: music manager example
Here's a Spring Boot 1.5, Spring Data Rest, Lombok, and Jackson implementation (GitHub).
Music
#Data
#NoArgsConstructor
#Entity
public class Music {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#OneToMany(cascade = { CascadeType.ALL }, orphanRemoval = true)
private List<Album> albums;
#OneToMany(cascade = { CascadeType.ALL }, orphanRemoval = true)
private List<Person> artists;
}
Album
#Data
#NoArgsConstructor
#Entity
public class Album {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String title;
#ManyToOne(cascade = { CascadeType.ALL })
private Person artist;
#OneToMany(cascade = { CascadeType.ALL }, orphanRemoval = true)
private List<Track> tracks;
}
Track
#Data
#NoArgsConstructor
#Entity
public class Track {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String title;
#JsonSerialize(using = MyDurationSerializer.class)
private Duration duration;
#ManyToMany(cascade = { CascadeType.ALL })
private List<Person> musicians;
public Track(String title, String duration, List<Person> musicians) {
this.title = title;
this.duration = Duration.parse(duration);
this.musicians = musicians;
}
}
Person
#Data
#NoArgsConstructor
#Entity
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String firstName;
private String lastName;
#JsonSerialize(using = MyLocalDateSerializer.class)
private LocalDate birthDate;
public Person(String firstName, String lastName, String birthDate) {
this.firstName = firstName;
this.lastName = lastName;
this.birthDate = LocalDate.parse(birthDate);
}
}
MyDurationSerializer
public class MyDurationSerializer extends StdSerializer<Duration> {
private static final long serialVersionUID = 1L;
protected MyDurationSerializer() {
super(Duration.class);
}
#Override
public void serialize(Duration value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeString(value.toString());
}
}
MyLocalDateSerializer
public class MyLocalDateSerializer extends StdSerializer<LocalDate> {
private static final long serialVersionUID = 1L;
private DateTimeFormatter FORMATTER = ofPattern("yyyy-MM-dd");
protected MyLocalDateSerializer() {
super(LocalDate.class);
}
#Override
public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeString(value.format(FORMATTER));
}
}
Spring Data REST HATEOAS representation
curl http://localhost:4000/albums/1/tracks
{ "id" : 1,
"albums" : [ {
"id" : 1,
"title" : "Kind Of Blue",
"artist" : "#{
"id" : 1,
"firstName" : "Miles",
"lastName" : "Davis",
"birthDate" : "1926-05-26"
},
"tracks" : [ {
"id" : 1,
"title" : "So What",
"duration" : "PT9M5S",
"musicians" : [ {
"id" : 1,
"firstName" : "Miles",
"lastName" : "Davis",
"birthDate" : "1926-05-26"
}, {
"id" : 2,
"firstName" : "Bill",
"lastName" : "Evans",
"birthDate" : "1929-09-16"
} ]
}, {
"id" : 3,
"title" : "Blue in Green",
"duration" : "PT5M29S",
"musicians" : [ {
"id" : 1,
"firstName" : "Miles",
"lastName" : "Davis",
"birthDate" : "1926-05-26"
}, {
"id" : 2,
"firstName" : "Bill",
"lastName" : "Evans",
"birthDate" : "1929-09-16"
} ]
} ]
} ],
"artists" : [ {
"id" : 15,
"firstName" : "Miles",
"lastName" : "Davis",
"birthDate" : "1926-05-26"
}, {
"id" : 16,
"firstName" : "Bill",
"lastName" : "Evans",
"birthDate" : "1929-09-16"
} ]
}

Categories

Resources