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
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.
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")
}]
}
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
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
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"
} ]
}