How to avoid services in DtoMappers layer - java

Good day, I have a Spring Boot based backend , we are using own library to convert JPA entities to Dto's (library works based on reflection).
The problem is , we inject service layer directly to some mappers. Let's say I have a UserEntity and UserDto.
UserDto has a field called avatar and avatars are stored in S3.
So in order to build a UserDto we are using the code like this.
#Component
class UserMapper {
#Inject
S3Service s3Service;
public UserDto toDto(UserEntity entity){
UserDto dto = new UserDto();
BeanUtils.copy(entity,dto);
dto.setAvatar(s3Service.getAvatarByUser(entity));
}
}
I don't like this approach because Mapper mustn't know anything about Service layer . However this mapper is used by other mappers as well. In case I want to return an OrderDto, it has a nested UserDto so OrderDto calls UserMapper internally.
Are there any best practices for Mappers to be service free ?
So far I tried the following.
Store avatar in ThreadLocal cache. When controller calls a service to get a user, service will store user's avatar in the ThreadLocal, and then Mapper will get it from ThreadLocal cache. Disadvantage - it's hard to test it and requires me to make Mocks
Create a separate POJO called UserWithAvatar that stores UserEntity entity;String avatar and create a mapper for UserWithAvatar instead of UserEntity. Disadvantage - as I said this mapper will be used by OrderMapper and order mapper takes OrderEntity with nested UserEntity instead of UserWithAvatar

I think mapper should be inside of service but I will try working with ur requirements
u have 2 choices:
You inject both service and mapper to controller, get entity back to the controller and map it using mapper before returning response
Use event publishing to publish an event which mapper then catches and produces the mapping. After that you could either directly return the dto to controller or produce another event. (event publishing is by default synchroneous so you dont have to worry about concurrency issues)
Event publishing is done via spring and results in very uncoupled code where publisher doesnt know anything about event subscribers and hence these 2 can be in 2 seperate layers that wont know anything about each other
Easy to follow guide: https://www.baeldung.com/spring-events

Related

Data not saved in db when the time #PostPersist got called

I need to send a request to other microService once the object got created in the database. I only send the object id so other microService needs to call the db again for the info with bunch of other stuff.
But, when the other microService try to lookup for the record using the received id it cannot find the saved record in the database.
I tried debug seems like record does not persist even though #postPersist got called.
It will be saved after #PostPersist got executed.
Has anyone could give a workaround for this. I really need to query the database again as this is a custom requirement. I use mysql and spring boot
public class EmployeeListener {
#PostPersist
public void sendData(Employee employee){
Long id = employee.getEmployeeId();
RestTemplate restTemplate = new RestTemplate();
restTemplate.exchange("http://localhost:8081/service/employee"+id, HttpMethod.POST, null, String.class);
}
}
#Entity
#EntityListeners(EmployeeListener.class)
public class Employee {
//
}
The problem is that JPA lifecycle events happen in the same transaction as your save operation, but the lookup, since it happens with a different server must only happen after your transaction is closed.
I therefore recommend the following setup: Gather the ids that need informing in a Collection and then when the transaction is completed send the data.
If you want to have the send operation and save operation in one method, the [TransactionTemplate][1] might be nicer to use than transaction management by annotation.
You also might consider Domain Events. Note that they trigger only when save is actually called. The benefit of these events is that they get published using a ApplicationEventPublisher for which listeners are Spring Beans so you may inject whatever bean you find helpful. They still need a way to break out of the transaction as described above
#PostPersist annotated method is called within the same transaction and the default flash mode is AUTO, that's why you don't see the record in the database. You need to force a flush:
#Component
public class EmployeeListener {
#PersistenceContext
private EntityManager entityManager;
#PostPersist
public void sendData(Employee employee){
// Send it to database
entityManager.flush();
Long id = employee.getEmployeeId();
RestTemplate restTemplate = new RestTemplate();
restTemplate.exchange("http://localhost:8081/service/employee"+id, HttpMethod.POST, null, String.class);
}
}
Notice that EmployeeListener needs to be a Spring managed bean.

How to structure controllers that communicate with databases

I'm pretty new to the concept of patterns. I am practising my dependency injection skills as well as using DAO principles. The code I have written works but I feel that it can be written in a more elegant fashion. I've tried restructuring it a pattern I saw but that complicated things so not sure if I implemented it correctly. As a general rule when a web application communicates with a database and throws out result, how should one structure their project?
I've heard of the MVC principle but that doesn't necessarily add database to the mix.
This is what I have so far:
A class containing a controller in a Controller package:
#RestController
public class ResponseController {
#Autowired
MongoBase dbConnection;
#RequestMapping(value = "/jsonresult", method = RequestMethod.GET)
#ResponseBody
public String jsonresult(#RequestParam(value = "id", required = true) String id){
return dbConnection.documentToJSON(id, Constants.database,Constants.collection);
}
#RequestMapping(value = "/alljsonresult", method = RequestMethod.GET)
#ResponseBody
public String alljsonresult(){
return dbConnection.allDocumentToJSON(Constants.database,Constants.collection);
}}
A class containing CRUD methods to the database in a Database package:
#Component
public class MongoBase {
#Autowired
MongoClient mongoClient;
public MongoBase() {
try {
mongoClient = new MongoClient("localhost", 27017);
} catch (Exception e) {
e.printStackTrace();
}
}
public void printAllCollection(String databaseName, String collectionName) {
...
}
So is there a better way/more efficient way of writing thi? Also I feel I haven't fully implemented DI in the Monogbase class since it contains the new keyword..
If you are using springboot, then you don't need this old style
also don't need to create mongoClient bean your self, spring boot help you in it
You just need to add following properties in application.properties file
#mongodb
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=app1
Also declares a spring-boot-starter-data-mongodb in your pom or gradle
it's a cool and super awesome dependency for accessing Data with MongoDB
you can read about it from here[https://spring.io/guides/gs/accessing-data-mongodb/]
suppose you have a domain
#Document(collection = "domain")
public class User {
#Id
private long id;
#Indexed(unique = true)
private String domain;
private boolean displayAds;
//getters and setters
}
Now if we need to perform curd operation on this domain, extends MongoRepository, you have CRUD function automatically. Spring data come with many magic findBy queries, review the official Spring data MongoDB – Query methods for detail.
public interface UserRepository extends MongoRepository<User, Long> {
Domain findFirstByDomain(String domain);
Domain findByDomainAndDisplayAds(String domain, boolean displayAds);
//Supports native JSON query string
#Query("{domain:'?0'}")
Domain findCustomByDomain(String domain);
#Query("{domain: { $regex: ?0 } })")
List<Domain> findCustomByRegExDomain(String domain);
}
UserRepository extends the MongoRepository interface and plugs in the type of values and id it works with: User and Long. Out-of-the-box, this interface comes with many operations, including standard CRUD operations (create-read-update-delete).
now you can easly use it in your controller
#RestController
public class ResponseController {
#Autowired
UserRepository userRepository;
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
User create(#RequestBody #Valid User user) {
return userRepository.create(user);
}
}
also you can do with it lot of things. you just need to go throw with it doc.
Also you you can use mongoTemplate for execute the query
#Autowired
MongoTemplate mongoTemplate;
When I build web applications I typically define the full chain as follows:
Client Side:
View - This is the V in MVC where you control visuals & user action derived workflow.
Controller - This is the C in MVC where workflow is managed. Most Client processing will go here and multiple Client calls can be made to get/send data or perform lookups.
Client - This is where you make a call to a REST web service and parse/deserialize the results/handle exceptions.
Server Side:
RestController (Sometimes Called Resource) - This is your REST API endpoint. Here you extract & validate a request.
Service - This is where most of your server logic will go. Sometimes you might have to make multiple data access calls or call other service functions.
DataAccessObject (Sometimes Called Provider) - This is your database interaction to pull data from your database into a model. CRUD operations (Create Read Update Delete)
Example Scenario:
Lets say we want to submit data & permissions for a given user
UserView.jsp - User types in user & permission data and hits submit.
UserController.java - validates User & permission data, does any necessary lookups, then calls UserClient.
UserClient.java - Builds the REST request and calls the /user/create REST endpoint.
UserRestController.java - Unpackages/Validates the request, then calls UserManagementService
UserManagementService.java - Server Logic happens here! Lets say I have two tables in my database. A User table and a Permissions table. I want to store the user information in the User table and the permission information in the permission table so I will call the UserDAO for the user data and the PermissionDAO for the permission data.
UserDAO & PermissionDAO - Saves The passed models to their respective tables.
Return to Service, Return to RestController, Return to Client (Parse Response), Return to Controller (Move the Workflow forward with a redirect or a success message).
Conclusion:
This may seem like a lot of in-between steps but this design provides a ton of flexibility, especially if your building large, complex web services. Each component has a specific purpose, follows an easy naming convention, and splits complex logic into smaller, simpler steps.
I'd like to recommend some improvements to your solution:
You're using Spring. You should not create any injected beans using new. Let Spring instantiate and manage those beans for you.
Use the #Repository annotation to mark your persistence class.
Make your repository class interface based.
Don't embed "Mongo" into the class name. You happen to be using Mongo as your persistence provider now, but you may change your mind later. Don't reveal implementation information in your class names - hide it.
The Controller is part of the UI. It uses repositories and/or services to fulfill use cases. It's perfectly correct to use Spring to inject the repository into the Controller.
I'd recommend that you use Spring Boot, an opinionated version of Spring. Have a look at their guides to learn how to use it properly.

Need a way to annotate service methods following repository pattern

I'm trying to refactor the existing code base of one of my project following Repository pattern, so that i can make the project more re-usable and testable.
I've written services, repositories, when I try to set Authentication, Authorization and Transactional annotation on service layer, I am facing issues.
These annotations works only on controller level, but not on service layer, so I want a way for annotate service methods.
Is it possible to do so?
It would be helpful, if someone points me samples using repository pattern on Play framework or better way to proceed further.
Authentication and authorization only make sense on a request, so sticking them on anything but a controller method is not going to work either way.
Transactional is just a helper annotation to wrap the entire request in a JPA transaction. It is usually advisable to do the wrapping yourself anyway, so you don't really need that. Example taken from the documentation:
#Inject
private JPAApi jpaApi;
public void updateSomething() {
// do something with the entity manager, per instance
// save, update or query model objects.
jpaApi.withTransaction(() -> {
EntityManager em = jpaApi.em();
Query query = em.createNativeQuery("update people set active = 1 where age > 18");
query.executeUpdate();
});
}

Java Spring REST + MongoDB (custom URI? using MongoDB Template instead of respository class? what about the xml config files?)

I currently have been reading and trying out MongoDB with Spring REST framework.
I have the following code for the controller:
#RestController
#RequestMapping("/users")
public class UserController {
#Autowired
private UserRepository userRepo;
#RequestMapping(value = "/info2", method = RequestMethod.GET)
public List<User> getAllUser(){
List<User> users = userRepo.findByEmail("test#test.com");
return users;
}
#RequestMapping(value = "/save", method=RequestMethod.POST)
public User createUser(#RequestBody User user){
return userRepo.save(user);
}
}
However, when I call
localhost:8080/users, it returns back
{
_links: {
self: {
href: "http://localhost:8080/users{?page,size,sort}"
templated: true
}-
search: {
href: "http://localhost:8080/users/search"
}-
}-
page: {
size: 20
totalElements: 0
totalPages: 0
number: 0
}-
}
I want the URI /users/info2 to return back the list of users by that particular email. How do I do that?
Also, here are the outstanding questions I have:
Can I just use MongoDBTemplate instead of the MongoRepository? I want more customized queries, and I couldn't find any in depth examples on the web.
How does Spring framework map the xml config file, for example, in cases like when I setup multiple MongoDB connections?
So without your configs, but looking at your existing code and service response, one can make some general assumptions. Your Repository is annotated with #RepositoryRestController which not only provides Spring Data access but also exposes a common ReST endpoint for your repository.
This can be determined from two aspects of your post. First you don't appear to be using HATEOAS in your Controller class, yet your service exposes JSON + HAL. Furthermore your response exposes the paging and sorting feature of Mongo Repository as well as the search behavior of Spring Data Repositories when annotated with #RepositoryRestController.
If you don't want this behavior, change the annotation on your Repository to #Repository instead.
Also to answer your other questions:
1. you can annotate methods if you want with queries on Spring Data Repositories, you can also use any class in the stack managed by spring you want, but why?
I suggest reading about the bean lifecycle to understand the dependency management within spring, there are plenty of presentations (including one in my github repo). If you have multiple connections, you can define your repository beans to utilize anything you wire it. There is a lot more manual operations at that point, and it will take some understanding and through to make it work. There is no way to give you a simple "do xyz" type answer without a lot more information.

Design pattern for DTO

I have a web application using jdbc for database calls.
I have a service, dto and dao layer.
I have a request xml which is huge. Can I pass the request object to dao method or should I transfer the request to a dto model and then pass the dto object as a paramter to my dao method?
Which is the right approach??
public TestServiceClass addSurveySubmitDetails(TestRequestXML testRequestXML){
//call to dao method
TestDao = testdao = new TestDao(testRequestXML);
}
OR
public TestServiceClass addSurveySubmitDetails(TestRequestXML testRequestXML){
//create dto object
TestDTO testDTO = new TestDTO();
testDTO .setId(testRequestXML);
//call to dao method
TestDao = testdao = new TestDao(testDTO );
}
Which is the right approach??
I don't think there is a right or wrong answer. It's pretty subjective in my opinion.
But I personally like to have a thin layer between the controllers and the services (assuming you're using the MVC pattern), that its only task is to convert requests (XML, Json, etc) to domain objects.
It is quite useful when you have complex domain objects or aggregates of which you need to show information in a view.
It depends on your architecture, but as DTO is Data Transfer Object there's no reason to use them between service and dao layers.
You can have one for service layer I suppose like in code sample below, but anyway it depends on your application's architecture.
public TestServiceClass addSurveySubmitDetails(TestDTO testDTO){
TestRequestXML testRequestXML = testDTO.getId();
TestDao = testdao = new TestDao(testRequestXML);
}
More on DTO's
Data Transfer Object
LocalDTO
YAGNI is good idea, keep it simple design, where possible
DTOs are really intended for remote calls. If you're sending data over the network to a different virtual machine, use a DTO. If you're sending data to another local class on the same virtual machine, don't bother with a DTO. A DTO is just an efficient way to transfer data remotely. It doesn't really have any advantages anywhere else.

Categories

Resources