I am searching for a better approach, that how to either exclude the auditing fields(like createdBy,createdDate) while fetching the #Entity in Data repository class or ignore them in API response. I know we can do it by using #Ignore or #IgnoreProperties on each property or entity class, but not interested to add it in every class , reason i have too many entities.
Is there any other approach to achieve with simple and with common implementation?
If all auditing fields have the same name, Use an abstract class to manage those fields, then other entirety extend from it;
here is my approach:
#MappedSuperclass
#EntityListeners(AuditingEntityListener::class)
abstract class ModifiedJpaEntity:Serializable {
companion object {
private const val serialVersionUID = -5554308939380869754L
}
#Column
#CreationTimestamp
#JsonIgnore
var createAt:Date?=null
#Column
#CreatedBy
#JsonIgnore
var createBy:String?=null
#Column
#UpdateTimestamp
#JsonIgnore
var updateAt:Date?=null
#Column
#LastModifiedBy
#JsonIgnore
var updateBy:String?=null
val createTimeStr: String
get() = if(createAt!=null) SimpleDateFormat("yyyy-MM-dd HH:mm").format(createAt) else ""
val updateTimeStr: String
get() = if(updateAt!=null) SimpleDateFormat("yyyy-MM-dd HH:mm").format(updateAt) else ""
}
Related
I am using JHipster(spring boot) to generate my project. I would like to hide/show fields in JSON from application.yml. for exemple:
I have the following class
#Entity
#Table(name = "port")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Port implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
#Column(name = "id")
private Long id;
#Column(name = "city")
private String city;
#Column(name = "description")
private String description;
//getters & setters
}
My GET method return a response like:
{
"id": 1,
"city": "boston",
"description": "test test"
}
I would like to be able to include/exclude some fields from application.yml (since i don't have application.properties) otherwise to have something like:
//application.yml
include: ['city']
exclude: ['description']
in this exemple my json should look like:
{
"id": 1,
"city": "boston",
}
for exemple if I have 40 fields and I need to hide 10 and show 30 I just want to put the 10 I want to hide in exclude in application.yml without go everytime to change the code. I guess #jsonignore hide fields but I don't know how to do it from application.yml
Sorry for not explaining well. I hope it's clear.
Thank you in advance for any suggestion or solution to do something similar
Spring boot by default uses Jackson JSON library to serialize your classes to Json. In that library there is an annotation #JsonIgnore which is used precisely for the purpose to tell Json engine to egnore a particular property from serialization/de-serialization. So, lets say in your entity Port you would want to exclude property city from showing. All you have to do is to annotate that property (or its getter method) with #JsonIgnore annotation:
#Column(name = "city")
#JsonIgnore
private String city;
You can try to create a hashmap in your controller to manage your HTTP response.
Map<String, Object> map = new HashMap<>();
map.put("id", Port.getId());
map.put("city", Port.getCity());
return map;
Basically you don't expose your Port entity in your REST controller, you expose a DTO (Data Transfer Object) that you value from your entity in service layer using a simple class (e.g PortMapper). PortDTO could also be a Map as suggested in other answer.
Your service layer can then use a configuration object (e.g. PortMapperConfiguration) that is valued from application.yml and used by PortMapper to conditionally call PortDTO setters from Port getters.
#ConfigurationProperties(prefix = "mapper", ignoreUnknownFields = false)
public class PortMapperConfiguration {
private List<String> include;
private List<String> exclude;
// getters/setters
}
#Service
public class PortMapper {
private PortMapperConfiguration configuration;
public PortMapper(PortMapperConfiguration configuration) {
this.configuration = configuration;
}
public PortDTO toDto(Port port) {
PortDTO dto = new PortDTO();
// Fill DTO based on configuration
return dto;
}
}
I have a Spring Boot application with the following entities:
#Data
#Entity
#Table(name = "jokes")
#EqualsAndHashCode(callSuper = true)
public class Joke extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "content")
private String content;
}
and
#Data
#MappedSuperclass
public abstract class BaseEntity {
#Column(updatable = false)
#CreationTimestamp
private LocalDateTime createdAt;
#UpdateTimestamp
private LocalDateTime updatedAt;
}
My Controller:
#PostMapping("/jokes")
public Joke createJoke(#Valid #RequestBody Joke joke) {
return jokeRepository.save(joke);
}
The fields createdAt and updatedAt are automatically updated. I am using swagger and when I go on an end point which allows me to create a new resource, then swagger gives me the option of updating the fields createdAt and updatedAt at as well as shown below. The are not actually being updated, but I would like to not see them there. Anyone knows how I could do this?
If you want the fileds to be hidden only at the Swagger level, you can do it with the #Schema annotation of Swagger
#Data
#MappedSuperclass
public abstract class BaseEntity {
#Column(updatable = false)
#CreationTimestamp
#Schema(hidden = true) // One way to do it
private LocalDateTime createdAt;
#UpdateTimestamp
#Schema(accessMode = READ_ONLY) // Other way to do it
private LocalDateTime updatedAt;
}
The difference between the two of them is, hidden will remove the property from Schema component which will make it unavailable for both request and response payloads while accessMode will hide it only for request payloads and not show the access mode in the Schema component as mentioned in the documentation.
accessMode:
Allows to specify the access mode (AccessMode.READ_ONLY, READ_WRITE) AccessMode.READ_ONLY: value will not be written to during a request but may be returned during a response. AccessMode.WRITE_ONLY: value will only be written to during a request but not returned during a response. AccessMode.READ_WRITE: value will be written to during a request and returned during a response.
hidden:
Allows schema to be marked as hidden.
And if you want it to be ignored by the JSON parser that you're using, you'll need something like JsonIgnore if you're using Jackson as the parser.
#Data
#MappedSuperclass
public abstract class BaseEntity {
#Column(updatable = false)
#CreationTimestamp
#JsonIgnore // Jackson will ignore this field
private LocalDateTime createdAt;
#UpdateTimestamp
#JsonIgnore // this will also be ignored
private LocalDateTime updatedAt;
}
I have the following Entity. In this I want to fetch all data except phoneNumber. What will be the best solution? It would be fine if I could do it with annotation.
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "employee_name")
private String name;
#Column(name = "gender")
private char gender;
#Column(name = "date_of_birth")
private String dob;
#Column(name = "skills")
private String[] skills;
#Column(name = "phone_number")
private String phoneNumber;
//getter setter
}
To tell what will be the best way to do this you have to say why you want to do this and what you want to achieve.
There are many options:
omit the getter
use a projection (DTO or interface)
use inhreitance
use inheritance with #MappedSuperclass
Can you please use #Transient on your field. If it is a subclass of anyclass then on class level please use #Embedded.
If not then you need to read this as this is always lazy fetch From Hibernate, Chapter 19. Improving performance:
Lazy attribute fetching: an attribute or single valued association is fetched when the instance variable is accessed. This approach requires buildtime bytecode instrumentation and is rarely necessary.
You can use #Column(insertable = true, updatable = false) and I am not sure if we can ignore while fetching using entity. you can achieve your requirements using JPA Projections
Also,#JsonIgnore may be useful. it is used to tell Jackson to ignore a certain property of a Java object but
I have an Entity
#Entity
#Table(name = "EVENT")
public class Event {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private Long id;
#Column(name = "EVENT", columnDefinition="VARCHAR(100)", nullable = false)
private String event;
#Column(name = "DATE", columnDefinition="DATETIME", nullable = false)
#Convert(converter = InstantConverter.class)
private Instant date;
}
And a SearchParams class where all of the fields are optional
public class SearchParams {
private Long id;
private Instant startDate;
private Instant endDate;
private String event;
public Optional<Long> getID() {
return Optional.ofNullable(id);
}
// ... Similar for other fields ...
}
I would like to be able to search like:
public List<Event> search(SearchParams searchParams) {
// Do something with Entity Manager/another hibernate class to create a custom query based off the search params.
return events;
}
What's the easiest way to achieve this in JPA? Or is this not the right framework to use?
I could always resort to sql string building but its not a nice way of doing it.
As far as remember JPA has method where, which takes array of Predicates as parameter.
So what you could do is create dynamic list of predicates from your params and then pass it to your query.
so your code will be something like that
List<Predicate> predicates= new ArrayList<>();
if (!searchParams.getId().isEmpty()){
predicates.add(cb.equal(root.get("id"), searchParams.getId());
}
....
query.where(predicates.toArray(new Predicate[predicates.size()]));
The Spring Data JPA query-by-example technique uses Examples and ExampleMatchers to convert entity instances into the underlying query. The current official documentation clarifies that only exact matching is available for non-string attributes. Since your requirement involves a Date field, you can only have exact matching with the query-by-example technique.
Refer https://stackoverflow.com/a/39555487/4939174
You can also refer this link for Spring Data JPA - Specifications and Querydsl
I have a requirement to combine 2 entity objects into 1 model object that will be used to return data back to a calling api method. Is there a common pattern or solution for this scenario?
#Entity
public class Entity1{
#Column
private String value1;
#Column
private String value2;
}
#Entity
public class Entity2{
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "value1")
private Entity1 entity1;
#Column
private String value3;
}
For me you should use a Facade or a Business Delegator, that should return the object like a Adaptor of the two.
Entity2 already has Entity1, so it's sufficient to return an instance on entity2.
If you want to simplify your API, you should make a new model that combines properties of both and do the mapping behind the scenes.