I have two functions to encrypt and decrypt data.
My current code is as below. I have entity class, DTO class, repository and service class.
The name need to be encrypted before save to database and to be decrypted when retrieve from database.
Lets say I have 10 different entity classes need to do the encryption and decryption data, I need to add the encryption and decryption function to each service class as below codes.
Is there any way to do all the encryption and decryption data in one service class for all the entity? like overriding the Get and Set method in entity? Anyone can advice? Thanks a lot.
#Entity
#Getter
#Setter
public class Customer {
private Long id;
private String name;
private String contact;
}
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class CustomerDTO {
private String name;
}
#Repository
public interface CustomerRepository extends JpaRepository<Customer, Long>{
}
#Service
public class CustomerService {
#Autowired
private CustomerRepository customerRepository;
#Autowired
private EncrytionService encrytionService;
public void save(String name){
Customer customer = new Customer();
customer.setName(encrytionService.doEncrypt(name));
customerRepository.save(customer);
}
public CustomerDTO getCustomer(Long customerId) {
Customer customer = customerRepository.findById(customerId);
CustomerDTO dto = new CustomerDTO();
dto.setName(encrytionService.doDecrypt(customer.getName()));
return dto;
}
}
Not sure there is a way to do that easily (kinda out-of-the-box way), but maybe you could try to implement something yourself using JPA lifecycle events and EntityListener.
For example:
// this is going to be our EntityListener
public class SensitiveDataListener {
#PrePersist
void beforeAnyPersist(Customer customer) {
// encrypt what you need and set
// e.g. customer.setName(encrytionService.doEncrypt(customer.getName()));
}
// after an entity has been loaded
#PostLoad
void afterLoad(Customer customer) {
// decrypt what you need
}
}
// and this is how you add it to your entity
#EntityListeners(SensitiveDataListener.class)
#Entity
public class Customer {
//...
}
A good question here would be - ok I have multiple entities, what do I do - create multiple **Listener classes? In general, no. Your listener can "handle" multiple entities, but how to make it happen - depends on what you need - for instance, if you need to encrypt/decrypt different fields in different entity that's one case, and if you need encrypt/decrypt let's say name and you have this field in different entities, that would be another case and another solution. Also, you might want to encrypt everything and again that would be a different solution because it is yet another use case.
If it is the same field you could probably "unify" you entities (but keep in mind sometimes it is not a good idea when your entities implement some interfaces):
public interface Sensitive {
void setName(final Date date);
}
#EntityListeners(SensitiveDataListener.class)
#Entity
public class Entity1 implements Sensitive {
// override setName
}
#EntityListeners(SensitiveDataListener.class)
#Entity
public class Entity2 implements Sensitive {
// override setName
}
// but then your SensitiveDataListener will look like this
public class SensitiveDataListener {
#PrePersist
void beforeAnyPersist(Sensitive entity) {
// encrypt what you need and set
// e.g. entity.setName(encrytionService.doEncrypt(entity.getName()));
}
// after an entity has been loaded
#PostLoad
void afterLoad(Sensitive entity) {
// decrypt what you need
}
}
Maybe you could also use AttributeConverter, assuming your field is String and encoded value is also String you could create converter which will encode/decode your stuff, but then you need to add it to every field (in every entity) you want to encode.
Something like this:
#Convert(converter = MyAttributeConverter.class)
private String name; // this is entity field
Related
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.
So I have this case where the JPA entity is encrypted using it's own ID as salt.
Here is an example of doing the en/decrypt without annotation, I have to "manually" create custom get/setter to each encrypted fields.
StandardDbCipher is just my cipher class that accepts a salt during construction (which is in this case is the ID field). The password is already fixed in some other file.
#Entity
public class Applicant implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private String id;
private String profilePic;
private String contact;
private String personalInfo;
#Transient
private StandardDbCipher cipher;
private StandardDbCipher getCipher() {
if (cipher == null) {
cipher = new StandardDbCipher(id);
}
return cipher;
}
private String encrypt (String plain) {
return getCipher().decrypt(plain);
}
private String decrypt (String crypt) {
return getCipher().encrypt(crypt);
}
public String getProfilePic() {
return decrypt(profilePic);
}
public void setProfilePic(String profilePic) {
this.profilePic = encrypt(profilePic);
}
public String getContact() {
return decrypt(contact);
}
public void setContact(String contact) {
this.contact = encrypt(contact);
}
public String getPersonalInfo() {
return decrypt(personalInfo);
}
public void setPersonalInfo(String personalInfo) {
this.personalInfo = encrypt(personalInfo);
}
}
I would like to simplify the code and reduce boilerplate using #Converter, but couldn't figure out how to put the ID as salt? Any ideas? Maybe other annotation?
If it's something that you need to do in many entities, then I think you can try Aspect Oriented Programming (the most known implementation is AspectJ). Spring also has an integration with that (I've not worked with that as I'm not using Spring). The idea is that you can have some intercepting code that would be executed before or after a call to methods of your objects (in your case getter/setter methods of your entities) and inside them you can manipulate the actual object/parameters/return values.
You can call your encrypt method before the execution of setter method and pass the encrypted value to your setter. For the decryption, you run your decrypt method after the execution of the getter method.
By doing so, your entities would remain as a simple POJO and you don't need to provide a converter for each.
. Here are some tutorial demonstrating the AOP concept:
#AspectJ Based AOP with Spring
Introduction to Spring AOP
Update:
Another solution could be to use JPA Entity Listeners. You can do the encryption on #PrePersist and the decryption on #PostLoad callbacks in your entity or use a single listener class for all such entities. You would just need to annotate your POJOs like this:
#Entity
#EntityListeners(class=EncDecListener.class)
public class Applicant implements Serializable {
}
public class EncDecListener {
#PreUpdate
public void encrypt(Applicatnt a) {
// do encryption
}
#PostLoad
public void decrypt(Applicatnt a) {
// do decryption
}
}
I can create a repository via defining an interface on the appropriate JPA class A like the following:
public interface ARepository extends CrudRepository<A, Long>
{
}
and I can use that in my Controller (for example) via
#Autowired
private ARepository aRepository;
and just can do things like this:
aRepository.save(..);
aRepository.findAll();
..
No problem so far.
But my problem is that I have ca. 500 JPA classes and need to access each table which means to define 500 Repositories in the style of above.
So does exist an thing to create that either dynamically via some Spring Data "magic" which from my point of view should exist otherwise the above would not be possible. It looks like this is similar to my problem.
Apart from that one more issue related to the above. I can define findBy... methods in the interface and in the background there will be generated a query method for this particular attribute. The question is also if this can be done in a dynamic way related to the previous question, cause I have groups of tables which need supplemental query methods..
There is spring-data-generator which can automatically generate the interfaces for you.
Regarding your 2nd question I don't think you that can be done in a dynamic way. Java is statically compiled and there's no way to add members dynamically. There could be a tool that generates code for those methods but if that tool generates methods for all combinations of columns you will end up with a huge amount of methods.
You can make a base abstract entity for your 500 classes an then create one repo for this class. (I think it's a common practice to have a BaseEntity class with id, version etc. for every entity in the project).
For simple repo methods (like save, findAll etc.) it will work right from the box (note - entities must have the equal id type). For example:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstarct class BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
}
#Entity
public class Entity1 extends BaseEntity {
private String name;
}
#Entity
public class Entity2 extends BaseEntity {
private String name;
}
public interface BaseEntityRepo extends JpaRepository<BaseEntity, Long> {
}
Note that BaseEntity must have #Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) to prevent of using singe table base_entity for every entity. And their ids must not intersect (see #GeneratedValue(strategy = GenerationType.SEQUENCE)).
Usage:
#RunWith(SpringRunner.class)
#SpringBootTest
public class BaseEntityRepoTest {
#Autowired private BaseEntityRepo repo;
#Before
public void setUp() throws Exception {
repo.save(asList(
new Entity1("entity1"),
new Entity2("entity2")
));
}
#Test
public void readingTest() throws Exception {
List<BaseEntity> entities = repo.findAll();
assertThat(entities).hasSize(2);
}
}
Related to your second question you can use this approach:
public interface BaseEntityRepo extends JpaRepository<BaseEntity, Long> {
<T> T findById(Long id, Class<T> type);
}
Usage:
#Test
public void findById() {
final Entity1 entity1 = repo.findById(1L, Entity1.class);
final Entity2 entity2 = repo.findById(2L, Entity2.class);
assertThat(entity1).isNotNull();
assertThat(entity2).isNotNull();
}
But you can build repo query methods only for 'common' properties of inherited entities which are present in the base class. To make this method work you must move the name parameter to the BaseEntity:
<T> List<T> findAllByNameLike(String name, Class<T> type);
I have a simple REST service that returns user profile entity that has about 20 fields.
I need to implement a functionality to filter the data where last name is required but all other fields (first name, age, city, state, zip, etc. ) are optional.
Is there a way to do it using JpaRepository without creating a lot of if/else statements for every single combination of patamenters?
It is a use case for JPA criteria (available since JPA2).
In indeed as you want to write a dynamic query, above all, you don't want to hard-coded JPQL queries for each combination and you don't want concatenating chunks of JPQL either as this is error-prone and not checked at compile time.
Note that in any case (Criteria or JPQL) you should check for each possible option if the client has specified it to be able to take them into consideration in the query build.
Now, as you implement the JPARepository interface, you have two ways :
using List<T> findAll(#Nullable Specification<T> spec); provided by the JpaSpecificationExecutor interface that you can also implement in your custom repository.
Enrich the JPARepository with your own interface that defines a method findAll() and that takes as parameter an object containing values for the research. Then create a concrete class to implement JPARepository.
You would have so the ability to inject the EntityManager and to use the Criteria API.
JpaRepository interface also implements QueryByExampleExecutor interface which provides findAll method for getting data using Query by Example (QBE) technique. That method would be really applicable for your scenario and is actually ideal when entity has a lot of fields and you want user to be able to filter entities by some of them.
Let's say the entity is Person and you want to create endpoint for fetching persons whose properties are equal to the ones which are specified. That could be accomplished with the following code:
Entity class:
#Entity
public class Person implements Serializable {
private Long id;
private String firstName;
private String lastName;
private Integer age;
private String city;
private String state;
private String zipCode;
}
Controller class:
#Controller
public class PersonController {
private PersonService service;
private PersonController(PersonService service) {
this.service = service;
}
#GetMapping
public List<Person> getMatchingPersons(#RequestBody Person personFilter) {
return service.findMatchingPersons(personFilter);
}
}
Service class:
#Service
public class PersonService {
private PersonRepository repository;
private PersonService(PersonRepository repository) {
this.repository = repository;
}
public List<Person> getMatchingPersons(Person personFilter) {
return repository.findAll(Example.of(personFilter));
}
}
Repository class:
#Repository
public class PersonRepository implements JpaRepository<Person, Long> {
}
It's always best to return a DTO representation of an entity in the
REST response.
In your DTO, you can only map required fields from an entity and
ignore other optional parameters.
Check this out http://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application
I know this is a common question, but I haven't found another that solves my doubts.
Usually, if the project is small, I've persistence annotations in the same object that represents the domain object. This allows to load the entity from database and keep all the setters private, ensuring any instance is always in a valid state. Something like:
#Entity
class SomeEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String attribute1;
private String attribute2;
private String attribute3;
// ... other attributes
protected SomeEntity() {}
/* Public getters */
public Long getId() { ... }
public String getAttribute1() { ... }
public String getAttribute2() { ... }
/* Expose some behaviour */
public void updateAttributes(String attribute1, String attribute2) {
/* do some validations before updating */
}
}
My problem appears if I want to hava a different persistent model. Then I would have something like:
/* SomeEntity without persistent info */
class SomeEntity {
private Long id;
private String attribute1;
private String attribute2;
private String attribute3;
// ... other attributes
protected SomeEntity() {}
/* Public getters */
public Long getId() { ... }
public String getAttribute1() { ... }
public String getAttribute2() { ... }
/* Expose some behaviour */
public void updateAttributes(String attribute1, String attribute2) {
/* do some validations before updating */
}
}
and DAO:
#Entity
class SomeEntityDAO {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String attribute1;
private String attribute2;
private String attribute3;
public SomeEntityDAO() {}
/* All getters and setters */
}
My question is, how can I map SomeEntityDAO to SomeEntity without exposing SomeEntity's attributes?
If I create a constructor like: public SomeEntity(String attribute1, String attribute2, ...) {}, then anyone can create an invalid instance of SomeEntity. The same occurs if I make all setters public in SomeEntity.
I also don't think is a valid solution build the object using updateAttributes() since this will execute some validations I don't whant to execute at this point (we trust the data that's persistet in database).
I'm thinking in having all the setters protected, so the DAO can extend the Entity and have access to setters... but I'm not sure if this is a good option.
Which is the best or common approach to solve this problem?
I've had the same kind of problem. And looking around I've found no solution. Believe me, if it exists is well hidden somewhere. None that suggests what to do when you have to deal with an old project where ORM entities are everywhere and there's a big step between Domain and ORM model.
Given this, I've deducted that if you really want to keep your Domain entities pure (so non get and set - the latter I would NEVER accept!) you have to do some deals. Because there's no way to share the internals without giving the entities some extra knowledge. Beware, this doesn't mean that you have to make the Domain entities aware of the ORM layer, nor that you have to use getters. Just, what I've concluded, the Domain entities should have ways to expose them as a different model.
So, in conclusion, what I would do in your situation is to build up a Visitor pattern. The Domain entity EntityA would implement the EntityAVisitable interface to accept a EntityAVisitor or something like this.
interface EntityAVisitable {
accepts(EntityAVisitor visitor);
}
The builder implements the interface required by the Visitor, EntityAVisitor.
interface EntityAVisitor<T>{
setCombinedValue1_2(String attribute1_attribute2_combinedInEntity);
<T> build();
}
The build() function of the interface EntityAVisitor uses a generic type T. In this way the Domain entity is agnostic about the return type of the concrete implementation of the EntityAVisitor.
Is it perfect? No.
Perfect solution would be to get rid of the ORM (actually I would say that I hate them, because the way are used is most of the times wrong - but this is my personal thought).
Is it nice? No.
A nice solution is not allowed due to language restrictions (I suppose you use Java).
Does it a good work in encapsulating the real content of your Domain entity? Yes.
Not only, in this way you can decide exactly what could be exposed and how. So, in my opinion, is a good deal between keeping the entity pure and having to work with an ORM under the seat.
Domain entity should be self-validating meaning it should only validate itself based on it's internal values. If update requires validation that depends on external dependencies, then I would create an updater class that is responsible for the update. From the updater class, you can use specification pattern (as an injectable dependency) to implement the validation.
Use domain entities when modifying, and DTOs for read-only projections. There are performance and simplification gains when you use straight DTOs in read-only. This is used in CQRS patterns.
class SomeEntity {
private Long id;
private String attribute1;
private String attribute2;
private String attribute3;
// ... other attributes
public SomeEntity() {}
/* Public getters/setter */
public Long getId() { ... }
public String getAttribute1() { ... }
public String getAttribute2() { ... }
public Long setId() { ... }
public String setAttribute1() { ... }
public String setAttribute2() { ... }
}
//classes/interfaces named for clarity
class EntityUpdater implements IEntityUpdater {
public EntityUpdater (ISpecification spec){
}
public updateEntity(SomeEntity entity){
//assert/execute validation
}
}
Some ORMs allow setting entity values through field access (as opposed to setter methods).
JPA uses the #Access annotation. See What is the purpose of AccessType.FIELD, AccessType.PROPERTY and #Access
I created an ORM, sormula, that can use field access. See #Row fieldAccess and test case org.sormula.tests.fieldaccess.