I'm learning AOP and am comfortable with Pointcuts, Advices etc.
What am going to ask, am pretty sure is not possible, but want to ask anyways.
I have a method which takes a userId, fetches the user's record from a database and then does something to the record. I have like twenty different methods that do different things, but all of them take the userId as input and fetch the record from database. This to me looks like a cross cutting concern that can be pulled into an aspect.
But how? I know I can access the arguments (userId in this case), access the return value of the method and catch the methods exception. But how do I give the method something to work with (record in the database in this case?)
public String printUserDetails(String userId)
{
Record record = Database.fetchRecord(userId);
System.out.println(record.getDetails());
return record.getTitle();
}
So, is there a way to pull that database accessing code into an aspect?
One way I can think of is declare something like the following for input
class RequestObject
{
String userId;
Record record;
}
and inject the record in the Aspect and then call proceed(). But this somehow feels wrong.
IMO, resolving a user, using the userid, is not a cross-cutting concern and hence aspect is not the right way. The first landing page that receives a userId should actually resolve it to UserRecord and from then on, the userRecord should be the one moving around in the application.
A simple analogy I can draw to your scenario from one of my applications is, all authenticated servlets expect the servletRequest.getRemoteUser() to return the valid user login corresponding to the user sending the request. We decorated the HttpServletRequest to resolve this to a User object in our application and all the authenticated servlets downcast the HttpServletRequest to AuthenticatedServletRequest and extract this object. No one else within the application tries to resolve a user login anymore.
You cannot access a method's local variables from AspectJ if this is what you wanted to know.
The rest of the question is rather about design and the answer dependent on what you want to achieve. You can avoid code duplication in multiple methods using a template method design pattern. You can inject real or mock objects into classes if you refactor them to have a member instead of local variables. It is another question if you create the member by directly refactoring your classes or via AspectJ's (ITD)[http://www.eclipse.org/aspectj/doc/next/progguide/starting-aspectj.html#inter-type-declarations] mechanism. A third question would be if you possibly want to use an aspect for caching in order to avoid fetching the same object from the database multiple times.
I am not sure what exactly you want to achieve, so I cannot answer more specifically.
Related
I have the following class hierarchy
Promotion - abstract
- Coupon
- Sales
- Deals
(Coupons, Sales and Deals are all subclasses of Promotion).
and would like to determine the type of the object when exchanging data between the REST APIs (JSON) and the Client (Angular). Users can submit a Coupon or a Deal or a Sale. For instance when a coupon is sent from the client, I want to be able to know that this is coupon so that i can call the correct method.
To solve this problem I have declared a variable and an abstract method in Promotion.
protected String promotionType = getPromotionType();
protected abstract String getPromotionType();
In the subclasses for instance in Coupon I have something like this
protected String getPromotionType() {
return "coupon"
// OR return this.getClass().getSimpleName().toLowerCase();
}
This will automatically initialize the promotionType variable so that in the Controllers I can check if the object is Coupon or Sales or Deal. Remember that JSON send data in String formats so I must I have a way to determine the type of object coming.
In this case I will have a single controller to handle all my CRUD operations. In my controller method I will do something like::
#PostMapping public void create(#RequestBody Promotion){
// And inside here I will check the type of **promotionType**
}
Here am using Promotion as argument instead of any of the subclasses in the create() method.
My question is, is it the best way to solve this?
Or do I have to create a separate Controller for each of the subclass? I am looking for the best way to do it in the real world.
I am using Hibernate for my mappings.
My question is, is it the best way to solve this?
Answers to this question will always be opinion-based, especially, as we don't know about your entire application, not only technically but business-wise, and how the client-code consumes and displays the code.
Or do i have to create a separate Controller for each of the subclass?
No, not necessarily. If the code is and would probably stay simple - sometime you can anticipate this - it doesn't make sense to inflate the code. Having three Controllers instead of a single PromotionController will very likely increase redundant code. Otherwise, if the subclasseses are rather heterogeneous, three Controllers could be more advisable.
Another thought, you might have a (human) client that manages only the Deals and that client has special requirements leading to a bunch of customized rest interfaces only for the Deal, you'd probably like to have a separate Controller.
I am looking for the best way to do it in the real world.
There is no best way. Five developers have probably five opinions on how to solve this. And even if one is more reasonable for the time being, it may change on the next day due to or changed new business requirements.
The best way is to discuss this in the team, create a common sense and if unsure, let the lead architect decide which way to go. Imo, your approach seems quite ok. That's my 2 cents.
I am developing a spring application, where I have three layers as most of other spring apps. The Rest Controllers on front, Services in middle, and JPA repositories in behind. Now we have spring entities mapped to the db, in my case they are plain old java objects(POJO), with only some fields and getters and setters which I usually prefer and don't want to put any business logic in there. However, in this project, I find out that in a lot of services I am repeating the same piece of code, something like that
User user=userRepository.findUserByName("some name here");
if(user==null){
throw new UserNotFoundException("User not found");
}
Now, this is not only for a single entity, there are many other similar repeated parts too. So, I have started to worry about it and looking possible areas to push that code and eliminate the repeated parts. One thing makes sens as stated in domain driven design, put that business logic inside the entity, now they will have both data and part of business logic. Is that a common practice?
Pretty much looks like a simple code reuse problem. If you are always throwing the same exception in all contexts then what about implementing a findExistingUserByName method on the repository that throws if the user doesn't exist?
Your code would become:
User user = userRepository.findExistingUserByName("username");
If you do not want to change the repository contract you could also implement a UserFinderService at the application level which wraps over a UserRepository and provides that service-level behavior.
Another more generic idea could be to implement a generic method and make it available to your application services either by inheritance, composition or a static class which would allow you to do something like:
withExistingAggregate<User>(userRepository.findUserByName("username"), (User user) -> ...)
You cat return Optional<User> from repository in this and similar cases.
Then you service code will look like:
userRepository.findUserByName("some name here")
.ifPresent(user -> doThmsWithUser(user));
I have multiple databases of users that I have to search on. The user can have multiple instances and the app checks if the user is a duplicate across the different databases.
So each user is associated with a client, and the fields are populated differently based on what client it is. (I know it's not right, but this is inherited application) My thought would be to refactor it by adding the client as a parameter into the getUserData method. However i'm realizing this is a change preventer smell. There are many wrapper methods that will pass in default values. i also have to traverse the call hiearchy far back enough that I would have access to the client object to pass in. This may be for or five method calls, so I would have to change those as well. At this point, the way the app was developed(by other developers) is very rigid when it comes to this, and I am looking to improve it.
The getUserData method:
public User getUserData(String userId, boolean fullUserRecord, Date userStartDate){
//retrive userdata from db
//attach client specific data for user
}
Example of a wrapper method:
public User getUserData(String userId, Date userStartDate){
getUserData(userId, false, userStartDate)
}
My question would be, how do I best handle this. Currently i am going down the rabbit hole of changing the method signature, but if this needs to change again, I would have to do the same thing, which won't be fun.
The wrapper methods serve no purpose whatsoever.
Introduce a parameter object and inline the wrapper methods where possible.
"Introduce parameter object" refactoring:
http://refactoring.com/catalog/introduceParameterObject.html
https://sourcemaking.com/refactoring/introduce-parameter-object
I'm currently working on an application where I can see the following:
Controller A : service.getSession(userId, Status.Started);
Controller B: service.getSession(userId, Status.Done);
(where Status represent an enum of possible statuses)
Service: getSession(Long id, Status status);
I find it not right, as users who are going to access controller A have certain roles and users accessing B others and there should be 2 services methods:
getSessionReady(Long id);
getSessionClosed(Long id);
Doing so I can clearly use Spring security and make sure that the right role access the right service methods. It makes me create two methods but it makes easier to secure the app and the goal of the service layer is to actually restrict access to limit logic errors right?
Yes. The more generic you make the service layer (or any class, in fact), the less value it adds.
You want your service layer to restrict access and make sure only valid calls make it into the domain.
Also, more methods is not a bad thing! As long as they make sense, feel free. Usually a method with an extra parameter that triggers different behaviour is a code smell, and should be split up.
If I want to introduce the concept of blocked users, where is the most appropriate place to make the check if a user is blocked, without breaking the principles of good design?
Till now, I've been using Spring Security, to annotate the controller methods on whether a particular user has the permissions to do a certain action. With this blocked users thing, it gets a bit more complicated. Should I try to fit this again in the controller (possibly with Spring security again) or this is something which I should let the domain object decide itself?
I guess it'd be better to leave this on the controller leve, but I fear if my controllers won't turn into an if...else mess one day.
One approach could be to introduce role called "BLOCKED", assign it to all users when they are blocked and annotate all methods that do not allow blocked users to access them with:
#PreAuthorize("!hasRole('BLOCKED')")
public void secureMethod();
Another approach would be to store blocked status in user database or in some other storage. Then extend the UserDetailsService to return additional user information including the "blocked" flag. And the again use security EL to filter methods that do not allow blocked users to execute them:
#PreAuthorize("!principal.blocked")
public void secureMethod();
UPDATE:
Problem you mentioned in the comments can be approached in some similar way:
#PreAuthorize("!#photo.owner.blockedUsers.contains(principal.name)")
public void likePhoto(Photo photo);
For any more complex and/or generic rules I would advice to use AOP aspects to keep your code clean from too many ifs.