spring data elasticsearch field mapping - elasticsearch

I have a badly designed document structure:
{
"_index": "items",
"_type": "item",
"_id": "CD5D8F6516A88805FA826C10777B1750D9AAF5DA9CDD8E264757AB7EEC22B1EB",
"_score": 1,
"_source": {
"title": "Textverständnis 5",
"active": true,
"successorId": null,
"metadata": {
"Fach": "DE",
"Kompetenz": "Les",
"code": "C_SX_DE_Les_A0016_00149_V00",
...
}
}
}
I would like to retrieve the the title, Fach, and code from the above document.
#Document(indexName = "items", type = "item")
#Data
public class Item {
#Id
private String id;
private String title;
private Metadata metadata;
#Data
static class Metadata {
private String Fach;
private String code;
}
}
Retrieving the title, code are ok, but the Fach field returns null. Do you know how could I map this field? It seems the issue is with the upper case, but unfortunately I cannot change the document structure.
Could you help?
Thanks.

was solved using Jackson's #JsonProperty annotation like:
#Document(indexName = "items", type = "item")
#Data
public class Item {
#Id
private String id;
private String title;
private Metadata metadata;
#Data
static class Metadata {
#JsonProperty("Fach")
private String subject;
private String code;
}
}

Related

to serialize a list of objects as a list of strings by suppressing irrelevant tags in the object

I am using Spring Boot to create a Rest Service to return some Json. Below is the model in question, in which I am suppressing the id from being serialized to Json with #JsonIgnore
//imports
#Entity
#Table(name="tags")
public class Tag {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id")
private int id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="post_id")
#JsonBackReference
private Post post;
#Column(name="tag")
private String tag;
//....
#JsonIgnore
public int getId() {
return id;
}
#JsonSetter
public void setId(int id) {
this.id = id;
}
//...
}
But I would also like to suppress the "tag" tag. That is, I'd like the output to look like a String array rather than array of Javascript objects containing a string.
The current output is:
{
"id": 1,
"title": "welcome to the blog",
"body": "Lorem, ipsum...",
"tags" : [
{"tag" : "webdev"},
{"tag" : "coding"},
{"tag" : "news"}
]
}
But I would like to get the output like:
{
"id": 1,
"title": "welcome to the blog",
"body": "Lorem, ipsum...",
"tags": [
"webdev",
"coding",
"news"
]
}
Can this be done with an annotation of some sort?

how can i avoid duplicate field in jackson in serialisation

I'm using Jackson to serialise My Rest Api
POJO :
#Data
#Entity
#NoArgsConstructor
#AllArgsConstructor
#JsonTypeInfo(include= JsonTypeInfo.As.WRAPPER_OBJECT,use= JsonTypeInfo.Id.NAME)
public class Project implements Serializable {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String projectName;
private String resource;
#ManyToMany
private List<Collaborator> collaborators;
#JsonIgnore
#OneToMany(mappedBy = "project",cascade = CascadeType.ALL)
private List<Task> tasks;
public Project(String projectName, String resource) {
this.projectName = projectName;
this.resource = resource;
}
}
output:
{
"id": 1,
"dateDebut": "2022-05-31T13:14:39.091+00:00",
"dateFin": "2022-05-31T13:14:39.091+00:00",
"project": {
"Project": {
"id": 2,
"projectName": "project Suivi Activite 2",
"resource": "resource 2",
"collaborators": []
}
},
"collaborator": null,
"days": []
}
how can i avoid field "Project" inside "project" ?
#JsonTypeInfo(include= JsonTypeInfo.As.WRAPPER_OBJECT,use= JsonTypeInfo.Id.NAME) ?

How to fix update process in Spring Boot (One-to-Many , One-to-One) via Postman?

I have a problem about updating the movie.
I wrote a function that is named for "update" in MovieService.
Here is that function which is shown below.
public void update(Long id,Movie movie) {
boolean isUpdatingEmployee = (movie.getId() == id);
if (isUpdatingEmployee) {
Movie existingMovie = movieRepository.findById(movie.getId()).get();
existingMovie.setId(id);
existingMovie.setName(movie.getName());
existingMovie.setRating(movie.getRating());
existingMovie.setDirector(movie.getDirector());
existingMovie.setGenres(movie.getGenres());
existingMovie.setCreatedAt(movie.getCreatedAt());
movieRepository.save(existingMovie);
}
}
When ı try to update a movie after saving it, I got this kind of JSON result and that's why the update process cannot be done.
http://localhost:8082/api/v1/movie/update/1
Body Request
{
"name": "MovieC",
"genres": [
{
"name" : "Adventure"
},
{
"name" : "Action"
}
],
"createdAt": "2021-04-28",
"rating" : 9,
"director" : {
"name" : "Director 2"
}
}
The result of JSON after updating the process.
{
"id": null,
"name": "MovieC",
"genres": [
{
"id": null,
"name": "Action"
},
{
"id": null,
"name": "Adventure"
}
],
"rating": 9.0,
"createdAt": "2021-04-28",
"director": {
"id": null,
"name": "Director 2"
}
}
Here is my Movie entity which is shown below.
#Entity
#Getter
#Setter
#ToString
#AllArgsConstructor
#NoArgsConstructor
public class Movie implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#JsonManagedReference
#OneToMany(mappedBy="movie",cascade = CascadeType.ALL,fetch = FetchType.EAGER)
private Set<Genre> genres;
private Double rating;
private LocalDate createdAt;
#ManyToOne(cascade=CascadeType.ALL,fetch = FetchType.EAGER)
#JoinColumn
private Director director;
}
Here is my Director entity which is shown below.
#Entity
#Getter
#Setter
#ToString
#RequiredArgsConstructor
#NoArgsConstructor
#JsonIgnoreProperties({"movies"})
public class Director implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NonNull
private String name;
#OneToMany(mappedBy="director",cascade = CascadeType.ALL,fetch = FetchType.EAGER)
private Set<Movie> movies;
}
Here is my Genre entity which is shown below.
#Entity
#Getter
#Setter
#ToString
#RequiredArgsConstructor
#NoArgsConstructor
#JsonIgnoreProperties({"movie"})
public class Genre implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NonNull
private String name;
#JsonBackReference
#ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinColumn
private Movie movie;
}
Here is my sample project link : Project Link
How can I fix it?
As per your code, this is your request:
http://localhost:8082/api/v1/movie/update/1
{
"name": "MovieC",
"genres": [
{
"name" : "Adventure"
},
{
"name" : "Action"
}
],
"createdAt": "2021-04-28",
"rating" : 9,
"director" : {
"name" : "Director 2"
}
}
Now consider this snippet from your code:
public void update(Long id,Movie movie) {
boolean isUpdatingEmployee = (movie.getId() == id);
if (isUpdatingEmployee) {
...
Your id will be 1 as you've set this in your path variable.
However, movie.getId() will be null since I don't see it in your RequestBody.
And so:
isUpdatingEmployee = (movie.getId() == id)`
isUpdatingEmployee = ( null == 1)
isUpdatingEmployee = false
this will always give you false so I don't think this will enter in your update logic.
I think the problem because you are returning the same object movie you passed in the body of the post method in the controller - https://github.com/Rapter1990/springboothazelcast/blob/3157f354a628d418cccb99cfdbd188f594c24e9c/src/main/java/com/springboot/hazelcast/controller/MovieController.java#L64
You should rewrite it to something like this:
#PostMapping("/save")
public Movie saveMovie(#RequestBody Movie movie) throws ParseException {
LOG.info("MovieController | Saving Movie.");
return movieService.save(movie);
}
Here is the link to CRUDRepository javadocs:
https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/CrudRepository.html#save-S-

Override related links in Spring Data REST

I'm using Spring Boot 2, Spring Data REST, Spring HATEOAS.
Let's say I've a model:
#EntityListeners({ContactListener.class})
#Data
#EqualsAndHashCode(callSuper = true)
#NoArgsConstructor
#AllArgsConstructor
#Builder
public class Contact extends AbstractEntity {
#NotNull
#Enumerated(EnumType.STRING)
#Column(nullable = false, columnDefinition = "VARCHAR(30) DEFAULT 'CUSTOMER'")
private ContactType type = ContactType.CUSTOMER;
#NotNull
#Enumerated(EnumType.STRING)
#Column(nullable = false, columnDefinition = "VARCHAR(30) DEFAULT 'NATURAL_PERSON'")
private PersonType personType = PersonType.NATURAL_PERSON;
private String firstName;
private String lastName;
private String companyName;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "store_id", updatable = false)
private Store store;
and Store:
#Data
#EqualsAndHashCode(callSuper = true)
#NoArgsConstructor
#AllArgsConstructor
#Builder
public class Store extends AbstractEntity {
#NotBlank
#Column(nullable = false)
private String name;
#Username
#NotBlank
#Length(max = 16)
#Column(nullable = false/*, unique = true*/)
#ColumnTransformer(write = "UPPER(?)")
private String code;
private String address;
private String zipCode;
private String city;
private String district;
When I get a contact the response looks like this:
{
"sid": "962732c2-68a8-413b-9762-f676d42046b4",
"createdBy": "1ccf2329-4aa3-4d55-8878-25517edf1522",
"createdDate": "2019-05-28T14:06:07.011Z",
"lastModifiedDate": "2019-06-04T08:46:02.591Z",
"lastModifiedBy": "system",
"createdByName": "Rossi Mario",
"lastModifiedByName": null,
"type": "CUSTOMER",
"personType": "NATURAL_PERSON",
"firstName": "Mario",
"lastName": "Rossi",
"companyName": null,
"fullName": "Rossi Mario",
"gender": "MALE",
"birthDate": "2019-05-21T00:00:00Z",
"birthCity": null,
"job": null,
"billingAddress": "Via 123",
"billingZipCode": "14018",
"billingCity": "Roatto",
"billingDistrict": "AT",
"billingCountry": "IT",
"shippingAddress": "Via 123",
"shippingZipCode": "14018",
"shippingCity": "Roatto",
"shippingDistrict": "AT",
"shippingCountry": "IT",
"taxCode": "XXXX",
"vatNumber": null,
"landlinePhone": null,
"mobilePhone": null,
"fax": null,
"email": "aaa#sdfg.it",
"certifiedEmail": null,
"survey": null,
"iban": null,
"swift": null,
"publicAdministration": false,
"sdiAccountId": "0000000",
"preset": false,
"_links": {
"self": {
"href": "http://localhost:8082/api/v1/contacts/1"
},
"contact": {
"href": "http://localhost:8082/api/v1/contacts/1{?projection}",
"templated": true
},
"store": {
"href": "http://localhost:8082/api/v1/contacts/1/store{?projection}",
"templated": true
}
}
}
as you can see the link of store it's not the self link of the resource Store.
I'd like to override that link setting the self resource. So I created this processor:
#Component
public class DocumentRowProcessor implements ResourceProcessor<Resource<Contact>> {
#Autowired
private BasePathAwareLinks service;
#Autowired
private EntityLinks entityLinks;
#Override
public Resource<Contact> process(Resource<Contact> resource) {
Store store = resource.getContent().getStore();
if(store != null){
resource.add(entityLinks.linkToSingleResource(store.getClass(), store.getId()).withRel("store"));
}
return resource;
}
}
Unfortunately, the link is now overriden but I find 2 links inside "store". Debugging I saw that inside the resource is present just the self link. My guess is that related links are added in following steps.
How can I accomplish my goal in a clean way?
The hateoas links are added the the result during serialization (using a specific JSON serializer), so you cannot remove it using a ResourceProcessor.
The hateoas link in the result is the proper link for that resource. http://localhost:8082/api/v1/contacts/1/store is the endpoint where you can check which store is linked to this contant, or you can delete/modify the association between this two object.
However in certain use-cases you need the self-link for further actions and you don't want to send an extra request from the client.
Do the following:
1. Create a projection for the contant.
2. Include all the properties you need and also the store.
3. If you don't need any properties of the store here - only the self link - then create an 'empty projection' for the store entoty and include that projection as store property into the contact property.
When you get this projection of the contact then the result will contain the self-link of the store inside the store property. So the main _links collection will be still a regular hateos link-collection but there will be a store._links.self.href property which will contain the self link of the associated store.

In springboot JPA one to one mapping response getting only values

Code for the controller class which will return response:
#RestController
#RequestMapping("/ProcessInfo/1.0.0")
public class RestController {
#ApiOperation(value = "getdeployments", notes = "This REST API is used to get deployments")
#GetMapping(value = "/getdeployments")
private List<ActivitiProcessDeployment> getdeployments() {
return ActivitiGetDeploymentRepository.getDeployment();
}
Below are the two entity classes having one to one mapping.
#Entity
#NamedQueries({#NamedQuery(name="ActivitiProcessDeployment.getDeployment", query="SELECT a.id,a.name,a.category,a.tenantId,a.deployTime,b.category,b.key,b.resource_name,b.version,b.deploymentId,b.diagramResourceName,b.description,b.id,b.hasStartFormKey,b.hasGraphicalNotation_,b.suspensionState,b.tenant_id_ FROM ActivitiProcessDeployment a INNER JOIN ActivitiProcessDefinition b ON a.id=b.deploymentId ORDER BY a.id")})
#Table(name="act_re_deployment")
public class ActivitiProcessDeployment implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#JsonProperty
#Column(name="id_")
private String id;
#JsonProperty
#Column(name="name_")
private String name;
#JsonProperty
#Column(name="category_")
private String category;
#JsonProperty
#Column(name="tenant_id_")
private String tenantId;
#JsonProperty
#Column(name="deploy_time_")
private Date deployTime;
#JsonProperty
#OneToOne( cascade = CascadeType.ALL,fetch = FetchType.LAZY)
#JoinColumn(name="deploymentId", nullable=true)
private ActivitiProcessDefinition activitiProcessDefinition;
}
Another entity class
#Entity
#Table(name="act_re_procdef")
public class ActivitiProcessDefinition implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#JsonProperty("process_def")
#Id
#Column(name="id_")
private String id;
#JsonIgnore
#Column(name="rev_")
private String rev;
#JsonProperty
#Column(name="category_")
private String category;
#JsonProperty
#Column(name="name_")
private String name;
#JsonProperty
#Column(name="key_")
private String key;
#JsonProperty
#Column(name="resource_name_")
private String resource_name;
#JsonProperty
#Column(name="version_")
private String version;
#JsonProperty
#Column(name="deployment_id_")
private String deploymentId;
}
JPA repository which is extending crud repository and calling the named query which is declared in the entity class.
#Repository
public interface ActivitiGetDeploymentRepository extends JpaRepository<ActivitiProcessDeployment, Long> {
public List<ActivitiProcessDeployment> getDeployment();
}
The response I'm getting is:
[
[
"1",
"ExecutionTaskListener",
null,
"-1234",
"2018-10-29T07:31:48.373+0000",
"http://www.activiti.org/test",
"myProcess",
"ExecutionTaskListener.bpmn20.xml",
"1",
"1",
"ExecutionTaskListener.myProcess.png",
null,
"myProcess:1:4",
"f",
"t",
"1",
"-1234"
],
[
"13",
"multiinstance (1)",
null,
"-1234",
"2018-10-29T07:31:49.901+0000",
"http://www.activiti.org/test",
"multiinstance",
"multiinstance.bpmn20.xml",
"1",
"13",
"multiinstance.multiinstance.png",
null,
"multiinstance:1:16",
"f",
"t",
"1",
"-1234"
],
[
"23",
"testing",
null,
"-1234",
"2018-10-29T07:31:50.591+0000",
"http://www.activiti.org/test",
"myProcess",
"testing.bpmn20.xml",
"2",
"23",
"testing.myProcess.png",
null,
"myProcess:2:26",
"f",
"t",
"1",
"-1234"
]
]
As shown in the above response I am getting only json values I mean only table values without column names. So, how to get json response mapped with response coresponding key.
I am not quite sure what you are trying to do and what actually happens (and why it is even possible). But as you can see your JSON is not a list of ActivitiProcessDeployment but a list of string lists.
Your named query does not return ActivitiProcessDeployments but a list of column values. Without any named query and an interface like below:
public interface ActivitiGetDeploymentRepository
extends JpaRepository<ActivitiProcessDeployment, Long> {
public List<ActivitiProcessDeployment> findAllOrderById();
}
you might get better results. It would not be flat as your JSON but ActivitiProcessDefinition would be nested inside your ActivitiProcessDeployment.
And if you need to do projection see this question & answer .

Resources