Jackson #JsonAlias annotation not working - java-8

The requirement is to deserialise "name", "first_name", "full_name" into name field. For this, I have used Jackson's #JsonAlias attribute. The version of Jackson being used is 2.9.5. For some reason, the deserialisation does not seem to be working as expected.
public class Profile {
#JsonAlias ({ "full_name", "first_name" })
private String name;
private String xyz;
private String xyzz;
}
When using:
return objectMapper.convertValue(response, objectMapper.getTypeFactory().constructCollectionType(List.class, Profile.class));
The full_name field does not get deserialised into the name field.

Related

How to do not send #IdClass object in Spring JSON queries

I'm setting a server to get a CRUD api from a postgresql Database using JPA. Everytime I want to expose an object from the DB it duplicate the idObject.
When I get an object from the database using springframework and send it after that, it duplicate the idObject like this:
{
"siteId": 3,
"contractId": "1",
"name": "sitenumber1",
"siteIdObject": {
"siteId": 3,
"contractId": "1"
}
}
SiteId and contractId are repeating...
but I want something like that:
{
"siteId": 3,
"contractId": "1",
"name": "sitenumber1"
}
I want to avoid using DTO because I think there is a better way but I don't find it. Since I'm using springFramework for just one or two month I'm maybe forgeting something...
there is the code:
Site code:
#Entity
#IdClass(SiteId.class)
#Table(name = "site", schema="public")
public class Site {
#Id
#Column(name="siteid")
private Integer siteId;
#Id
#Column(name="clientid")
private Integer contractId;
private String name;
#JsonIgnore
#OneToMany(cascade=CascadeType.ALL, mappedBy = "site")
public Set<Device> devices;
//setter, getter, hash, equals, tostring, constructor empty one and full one
SiteId code:
public class SiteId implements Serializable {
private Integer siteId;
private Integer contractId;
// setter, getter, constructor empty and full, hash and equals
Thanks to help :)
Bessaix Daniel
If you are using Spring you might also be using Jackson so if you annotate your SiteIdclass with #JsonIgnoreType it shouldn't be serialized at all when the Site object is serialized.
I am however unsure if this will break your application logic now that the id object is not serialized anymore.

How to remove some fields of an Object in Spring Boot response control?

this is one of my REST controller,
#RestController
#RequestMapping("/users/Ache")
public class Users {
#GetMapping
public User getUser() {
User user = new User();
return user;
}
}
As response, Spring boot will translate my Object to JSON,
this is response:
{
"username": "Ache",
"password": "eee",
"token": "W0wpuLAUQCwIH1r2ab85gWdJOiy2cp",
"email": null,
"birthday": null,
"createDatetime": "2019-03-15T01:39:11.000+0000",
"updateDatetime": null,
"phoneNumber": null
}
I want to remove password and token fields, How can I do?
I know two hard ways:
create a new hash map
and add some necessary fields, but it too complex
set those two fields to null
but it still leaves two null valued fields, it is too ugly.
Any better solution?
Spring leverages Jackson library for JSON marshalling by default. The easiest solution that comes to mind is making use of Jackson's #JsonIgnore but that would ignore the property on both serialization and de-serialization. So the right approach would be annotating the field with #JsonProperty(access = Access.WRITE_ONLY).
For instance, inside a hypothetical User class:
#JsonProperty(access = Access.WRITE_ONLY)
private String password;
#JsonProperty(access = Access.WRITE_ONLY)
private String token;
An alternative would be using #JsonIgnore only on the getter:
#JsonIgnore
public String getPassword() {
return this.password;
}
You can also create another class, for instance UserResponse with all the fields except password and token, and make it your return type. Of course it involves creating an object and populating it, but you leave your User class clean without Jackson annotations, and de-couples your model from your representation.
Keep the getter and setter but add the WRITE_ONLY JsonProperty. This way password validations will work when you use the entity as the request body.
#NotBlank
#JsonProperty(access = Access.WRITE_ONLY)
private String password;

Couchbase document id generation

I have an Springboot application integrated with couchbase 6.0.
I have read that if a key is annotated with #Id then it will saved as an document id and will not be a part of the json.
Then i have used #Id and #Field together on the key but still that field is not appearing on json document.
Can somebody help me out on the following:
1: How to make same key as document id and keep that a part of json also.
2: If a field is declared with #Id, it is created as document id and does
not appear on document, but when i do a get request same key appear on
the response.
I have also tried, click here https://docs.spring.io/spring-data/couchbase/docs/current/reference/html/#couchbase.autokeygeneration.usingattributes
My entity is:
#Id #GeneratedValue(strategy = GenerationStrategy.USE_ATTRIBUTES,delimiter="::")
private String id;
#IdAttribute
private String userid;
#Field
private String fname;
#Field
private String lname;
Post method body:
{
"id": "888",
"userid":"user1",
"fname": "xyz",
"lname": "abc"
}
In Couchbase server, it is saving this document as
It is creating document id as 888 only, it is supposed to generate documnet id as 888::user1
I have tested this many times but the result is same.
Looks like you're looking for Key generation using attributes:
It is a common practice to generate keys using a combination of the
document attributes. Key generation using attributes concatenates all
the attribute values annotated with IdAttribute, based on the ordering
provided similar to prefixes and suffixes.
So, for example you can do:
#Document
public class User {
#Id #GeneratedValue(strategy = USE_ATTRIBUTES)
private String id;
#IdAttribute
private String userid;
...
}
According to the example above you will get as a result a Document with the id = userId and also the field userId in the json.
UPDATE AS PER QUESTION EDIT
You may have to include a new filed in your entity, let's say postId and change the naming of the id field in your post method body by postId, something like:
Entity:
#Id #GeneratedValue(strategy = GenerationStrategy.USE_ATTRIBUTES,delimiter="::")
private String id;
#IdAttribute(order = 0)
private String postId;
#IdAttribute(order = 1)
private String userid;
#Field
private String fname;
#Field
private String lname;
Post method body:
{
"postId": "888",
"userid":"user1",
"fname": "xyz",
"lname": "abc"
}

Sending POST request with Postman with #DBref

I want to send a POST request with Postman that creates a Purchase object and save it in the database.
My class Purchase:
#Document(collection = "purchases")
public class Purchase {
#Id
private String id;
#DBRef
private User buyer;
#DBRef
private List<File> FilesToPurchase;
private Long timestamp;
public Purchase() { }
public Purchase(User buyer, List<File> filesToPurchase) {
this.buyer = buyer;
FilesToPurchase = filesToPurchase;
}
// Getters and setters not posted here.
I want to insert in the database a new purchase done by an already existing User "buyer" who wants to purchase a list of already exsting Files "FilesToPurchase".
I have in my controller a POST function that receives a Purchase object using the annotation #RequestBody, but so far I've got NullPointerExceptions because of the empty Purchase object received.
I don't know how to handle #DBRef annotation. In Postman I try sending a JSON like this:
{
"buyer": {
"$ref":"users",
"$id" : "ObjectId('5bb5d6634e5a7b2bea75d4a2')"
},
"FilesToPurchase": [
{ "$ref":"files",
"$id" : "ObjectId('5bb5d6634e5a7b2bea75d4a5')"
}
]
}
Rename field "FilesToPurchase" and setter to "filesToPurchase" to match java conventions and try this
{ "buyer": { "id" : "5bb5d6634e5a7b2bea75d4a2" }, "filesToPurchase": [ { "id" : "5bb5d6634e5a7b2bea75d4a5" } ] }
By marking controller parameter with #RequestBody you ask Spring to deserialize input json to java object(Jackson ObjectMapper is used by default). It will not automaticly populate the whole #Dbref field, you should do it yourself by querying mongo if you want, however the only field you need in referred object to save object that reffers it is 'id'.

#Field(type=FieldType.keyword) being ignored on certain properties

I'm having trouble with the way SD Elasticsearch is creating some of my indices on application startup. I've got some String fields that I want to be of type "keyword" but they are always being created as type "text". This is using Elasticsearch 5.5.1, Spring 5.0.0, Spring Data Kay-RELEASE.
As an example I've got something like follows:
// DepartmentSearchResult.java
#Document(indexName = "hr_index", type = "department", createIndex = false)
public class DepartmentSearchResult implements Serializable {
#Id private String id;
private String foo;
// other fields, getters, setters etc. omitted
}
// DepartmentSearchingRepository.java
public interface DepartmentSearchingRepository extends ElasticsearchRepository<DepartmentSearchResult, String> {}
// ApplicationStartupListener.java
#Component
public class ApplicationStartupListener implements ApplicationListener<ContextRefreshedEvent> {
#Autowired ElasticsearchTempalte elasticSearchTemplate;
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (!elasticSearchTemplate.indexExists(DepartmentSearchResult.class)) {
elasticSearchTemplate.createIndex(DepartmentSearchResult.class);
elasticSearchTemplate.putMapping(DepartmentSearchResult.class);
}
}
}
(I've set createIndex to false and have the ApplicationStartupListener instead due to an issue I asked about at How to correctly address "can't add a _parent field that points to an already existing type, that isn't already a parent" on app startup. Including it here in case this is somehow related.)
Anyway, I want DepartmentSearchResult.id to be keyword, not text. So, I've changed from:
#Id private String id;
to:
#Field(type=FieldType.keyword) #Id private String id;
I then drop the index and restart my app. The index and the mapping are created, but "id" is always created as text, not keyword. Other fields are working properly; if I change foo to #Field(type=FieldType.keyword) private String foo; that shows up as keyword in the mapping, it's just this id field that I can't get working.
My current workaround is to just create the mapping manually like:
curl -s -X PUT http://localhost:9200/hr_index/_mapping/department -d '{
"properties": {
"id": {
"type": "keyword"
}
}
}'
and that works, but I'd much prefer for Spring to just create the mapping on the fly so I don't need to maintain a separate mapping installation script. Any places I should be looking that might indicate why this field keeps getting created as "text"?

Resources