Persisting Full Data Binding POJO to Database - java

I have converted JSON response to POJO, following the concept of Full data binding.
POJO looks like this
public class User {
public Name _name;
#JsonCreator
public User(#JsonProperty("_name") Name _name,){
this._name=_name;
}
public static final class Name {
public String _first;
public Gender _gender;
#JsonCreator
public Name(#JsonProperty("_first") String _first,#JsonProperty("_gender") Gender _gender){
this._first = _first;
this._gender = _gender;
}
public static final class Gender {
public String age;
public Gender(#JsonProperty("age") String age){
this.age=age;
}
}
}
}
Now I need to persist this POJO, but I am not sure how should I do that efficiently, I have consider using Hibernate but I am unaware how to proceed.
How fields would be annotated in case I use Hibernate, since this is a complex POJO.
Is there a way I could use JDBC ? or any simpler and efficient way to achieve persistence with this kind of POJO.
Looking for a detail answer or an example or something that would clear my concept.
Thanks

Related

Is there an equivalent of Jackson + Spring's `#JsonView` using Quarkus + JSONB?

I'm playing with Quarkus and trying to build a CRUD REST application; I'm trying to get 2 endpoints returning 2 different views of the same entities. Here is an example on how I would have done in Spring + Jackson:
#Entity
public class Car{
public String model;
#ManyToOne( fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
public Owner owner;
// [...]
}
#Entity
public class Owner{
public String name;
// [...]
}
Here it is the important part: now if I were using Jackson I would have create a CarView class:
public class CarView {
public static class Public {};
public static class Private extends Public {};
}
And with that I would have annotated Car.model with #JsonView(CarView.Public.class) and Car.owner with #JsonView(CarView.Private.class) and then just annotate with the same annotations my methods in the REST controller in order to tell Jackson which view I want to use:
#RequestMapping("/car/{id}")
#JsonView(CarView.Public.class)
public Car getPublic(#PathVariable int id) { /*...*/ }
#RequestMapping("/car/private/{id}")
#JsonView(CarView.Private.class)
public Car getPrivate(#PathVariable int id) { /*...*/ }
Can I accomplish the same result using Quarkus & JSON-B?
Quarkus supports usage of JsonViews to manage the serialization/deserialization of request/response.
(Just to let you know, sadly it's not supported (yet) by smallry-openapi implementation, so even if the serialization would work, you'll still see the full model in swagger.)
An example of usage, taken from official guide https://quarkus.io/guides/resteasy-reactive#jsonview-support:
JAX-RS methods can be annotated with #JsonView in order to customize the serialization of the returned POJO, on a per method-basis. This is best explained with an example.
A typical use of #JsonView is to hide certain fields on certain methods. In that vein, let’s define two views:
public class Views {
public static class Public {
}
public static class Private extends Public {
}
}
Let’s assume we have the User POJO on which we want to hide some field during serialization. A simple example of this is:
public class User {
#JsonView(Views.Private.class)
public int id;
#JsonView(Views.Public.class)
public String name;
}
Depending on the JAX-RS method that returns this user, we might want to exclude the id field from serialization - for example you might want an insecure method to not expose this field. The way we can achieve that in RESTEasy Reactive is shown in the following example:
#JsonView(Views.Public.class)
#GET
#Path("/public")
public User userPublic() {
return testUser();
}
#JsonView(Views.Private.class)
#GET
#Path("/private")
public User userPrivate() {
return testUser();
}
When the result the userPublic method is serialized, the id field will not be contained in the response as the Public view does not include it. The result of userPrivate however will include the id as expected when serialized.
Have you checked #JsonbVisibility or "Jsonb adapter" part in
https://javaee.github.io/jsonb-spec/users-guide.html annotation from Jsonb? I am afraid maybe there isn't a solution in Jsonb yet like #JsonView in Jackson. Jsonb adapter is configuration at bean level(you choose the Jsonb instance when you (de)serialize), not at view level.

Spring Data JPA mapping nested entities

I'm a little bit confused about using projections in Spring Data JPA.
I wanted to optimize my queries by requesting only needed columns (preferably) in one query, and I thought that using projections is a good idea. But it seems that projection with nested projection becomes open and requests all columns and further nesting is impossible.
I've tried to find a solution with #Query (cannot find how to map nested lists), #EntityGraph (cannot find how to request only specified column) and #SqlResultSetMapping (cannot find how to make mapping nested lists), but it hasn't worked for me.
Is there any solution except receiving List<Object[]> and manually mapping?
I have the next entities classes (simplified for the question):
public class TestAttempt{
private Long id;
private User targetUser;
private Test test;
}
public class Test{
private Long id;
private String name;
private Set<Question> questions;
}
public class Question{
private Long id;
private String name;
private Test test;
}
And I wanted to write something like this (it can be just TestAttempt with null in unused fields):
public interface TestAttemptList {
Long getId();
Test getTest();
interface Test {
String getName();
List<Question> getQuestions();
interface Question {
String getName();
}
}
}
public interface TestAttemptRepository extends JpaRepository<TestAttempt, Long> {
List<TestAttemptList> getAllByTargetUserId(Long targetUserId);
}
And in result get something like this:
{
id: 1,
test: {
name: test1,
questions: [{
name: quest1
}, {
name: quest2
}]
}
}
Ive done something like this... You'll have your repository interfaces which will extend CrudRepository et. al. with the full objects (TestAttempt etc) You define your projections separately. The projection interfaces can contain other projection interfaces (TestAttemptSummary can contain a TestSummary) When the projection interface is used within the given repository the defined methods are applied to the object type the repository is configured for. Something like this.
public interface TestAttemptSummary {
Long getId();
TestSummary getTest();
}
public interface TestSummary {
String getName();
List<QuestionSummary> getQuestions();
}
public interface QuestionSummary {
String getName();
}
public interface TestAttemptRepository extends CrudRepository<TestAttempt, Long> {
TestAttemptSummary getTestAttemptSummary();
}

Mapping all request params into an object in Spring Controller [duplicate]

This question already has answers here:
In Spring-mvc the attribute names in view have to always match the property names in model?
(3 answers)
How to customize parameter names when binding Spring MVC command objects?
(10 answers)
Closed 3 years ago.
So, url requested looks like
localhost:8080/contacts?id=22&name=John&eventId=11
and also I got an object to map request into
public class ContactDTO {
private Long id;
private String name;
private Long eventId;
}
I use a controller method like passing my request params into an object
#GetMapping("/contacts")
public ContactDTO contacts(ContactDTO contact) {
// everything is awesome! contact maps clearly
return contact;
}
The question is how to map like this but have different name
localhost:8080/contacts?id=22&name=John&event_id=11
Setting #JsonAttribute doesn't works because Jackson mapper works only in requestbody.
Maybe I should write custom HandlerMethodArgumentResolver or something like that?
P.S.
I've got a dirty hack (objectMapper is injected, so I can use #JsonAttributes),
But this case fails on array mapping, same mapping with requestbody works fine
#GetMapping("/contacts")
public ContactsDTO contacts(#RequestParam Map<String,String> params) {
ContactDTO contactDTO = objectMapper.convertValue(params,ContactDTO.class);
return contactDTO;
}
Since it is an API design requirement, it should be clearly reflected in the corresponding DTO's and endpoints.
Usually, this kind of requirement stems from a parallel change and implies that the old type queries will be disabled during the contract phase.
You could approach the requirement by adding the required mapping "query-parameter-name-to-property-name" by adding it to the ContactDTO. The simplest way would be just to add an additional setter like below
public class ContactDTO {
private Long id;
private String name;
private Long eventId;
public void setEvent_id(Long eventId) {
this.eventId = eventId;
}
}
If you prefer immutable DTO's, then providing a proper constructor should work as well
#Value
public class ContactDTO {
private Long id;
private String name;
private Long eventId;
public ContactDTO(Long id, String name, String eventId, String event_id) {
this.id = id;
this.name = name;
this.eventId = eventId != null ? eventId : event_id;
}
}
Use something like
#RequestParam(name="event_id", required = true) long eventId
in the parameter list to change the parameter name.
Use #RequestBody insteaf of #requestparam.

Jackson - DTO int to String conversion

Working on a REST client that calls another server which returns the following object:
public class ObjectOriginal {
private int id;
private String name;
// constructor/getters/setters
}
I need to obfuscate the id. To do so I'm using an already existing service that transforms the id into a unique generated String so that the person calling my service doesn't know the REAL id but can still request info about it with the unique string.
So I'm basically trying to return to the caller this object:
public class ObjectNew {
private String id;
private String name;
// constructor/getters/setters
}
Do I need to have a copy of ObjectOriginalDTO + create a ObjectNew DTO + create a mapper to go from one to the other.
Or can I configure Jackson to deserialize the id field as a String and not an int?
You can do this using your own Serializer/Deserializer.
You have to implement your Serializer/Deserializer that will extends respectively BeanSerializerModifier/BeanDeserializerModifier and configuring your Module with them for instance Or use the annotation base solution as explained in this tutorial, there are plenty of references on the web for such a thing. then you'll have more controlle over the way to map your id.
If you don't want to have custom deserializer you can have:
public class ObjectNewDto {
private String id;
private String name;
// constructor/getters/setters
}
and another object:
public class ObjectOriginal {
private int id;
private String name;
// construxtor/getters/settes
}
Now after validating ObjectNewDto you can map it via your obfuscator service into ObjectOriginal , then validate this Object original and so on...

Serialize Jackson field in two different ways

I am doing POJO serialization / deserialization using Jackson.
Here is a POJO exemple :
public class Pojo {
public String productId;
public String name;
}
I have to read the field productId in this JSON :
{"productId":"1","name":"exemple"}
But also in :
{"_id":"1","name":"exemple"}
To make it short, I would like to use the same object to read the field in a JSON file found somewhere and to save the object as this in MongoDB, using productId as the primary key, which has to be named _id.
Since I am using Jackson (fasterxml) both to read from the file and to write to the database, I can not find a way to do so, except by creating a new class with the same fields (or inheritance) and fill them one by one. Basically, I would like to find a way to put 2 #JsonProperty annotations on productId.
Works with both strings:
public class Pojo {
#JsonProperty("_id")
public String productId;
public String name;
#JsonProperty("productId")
public void setProductId(String id) {
productId = id;
}
}

Categories

Resources