首页 > 解决方案 > Dynamic execution of the methods of bean object

问题描述

Currently i have one requirment our backend spring rest api will receive the data in encrypted json format (few fields are encrypted and few fields are plain text) and then applies the decryption ,then applies some business logic on the data ,finally stores data into database.

This decryption logic is repeatining muliple service implementations methods . So we desided to isolate the decryption logic from actual business logic.

i am using spring aop to decrypting the data and after decrypting same object i am passing to service layer methods.

But my service layer methods contains the different types of objects as arguments

Ex :

    processEmployee(EmployeeRequest request)

    procesStudent(StudentRequest request)

I was looking for a way how can i dynamically change the data on the same object fields it self ( Ex: EmployeeRequest,StudentRequest )

The following approach i have tried and stuck with 4th step.

1.Introduced a new annotation.

2.Annotate those fields which are having the encrypted data.

3.Retrieve all the annotated fields.

4.Each field data we will apply the decryption logic and decrypted data will be injected on the same field again

i was looking for the api to achieve 4th step ?

Is there any api available to dynamically execute the methods on the same object or any reference please point me .

标签: springspring-bootspring-aopspring-restcontrollerspring-rest

解决方案


My suggestion is to not use the same POJO for both encrypted / decrypted class. It make confusing for future usage (as if I received an EmployeeRequest instance, is it decrypted or not?), and also limit the type (as your encrypted/decrypted data must be the same type).

Now, for the implementation, you have two choices:

  1. Using explicit ConversionService

Register a converter:

@Component
public class EmployeeRequestConverter implements Converter<EmployeeRequest, EmployeeRequest> {

     @Override
     public EmployeeRequest convert(EmployeeRequest source) {
           // Apply your decryption logic
     }
}

Make the similar converters for other request objects.

Now in your controller:

public class MyController {

    private ConversionService conversionService;

    private MyService myService;

    @RequestMapping(...)
    public void aRequest(@RequestBody EmployeeRequest request) {
        myService.execute(conversionService.convert(request, EmployeeRequest.class));
    }

}
  1. Using reflection.

Precondition: You have @Encrypted annotation on encrypted fields.

Unlike the first solution, you do not create explicit converter for each type of request.

@Service
public class DecryptionService {

     public void <T> T decrypt(T input) {
          Field[] fields = input.getClass().getDeclaredFields();
          for (Field field : fields) {
               Encrypted encrypted = field.getAnnotation(Encrypted.class);
               if (encrypted != null) {
                   try{
                      field.setAccessible(true);
                      Object val = field.get(input);
                      // Base on @Encrypted annotation in your val, do the decryption
                      Object decryptedVal = ...;
                      field.set(input, decryptedVal);
                   } catch (Exception ex) {
                   }
               }
          }
     }
}

Now you can apply this service for your controllers.

You might want to cache the Class.getDeclaredFields() and the mapping between Class<?> -> @Encrypted fields for performance.


推荐阅读