Spring REST Hibernate Application Design - java

Environment :
Spring 4 REST
Spring MVC
Hibernate
Issue :
We are developing an application with below stack.
The Spring REST web service will expose APIs for client which will display it on UI (ASP .NET ) . The response is sent in JSON.
Consider below scenario :
Client calls REST api to get User with ID. The dao layer fetches User entity and will be delievred to client.
And below issues/observations for above scenario :
Since User can have another entities related with it throgh Hibernate mapping (like userRoles using oneToMany), these entities also need to be fetched, else LazyInitialization exception is thrown since UI tries to access these collections through User object.
Not all properties in User object will be required in response (e.g: some requests won't need roles a user have).
Considering above picture in mind , what is the best design approach to send User object (or response) to client through Spring REST??
Create an intermediate layer of objects (like DTOs) mimicking entity objects. Have this DTOs populated in Service layer as per requirement. Since service layer runs inside transaction issue number 1 will be resolved. But this requires extra copying between entity and DTOs
Handle issue number 1/2 at Hibernate entity / query level (join fetch queries or revamping mapping) and exclude properties not required in response through annotations like: #JsonIgnore. But this approach is not flexible and requires very careful design of entity classes
Can anybody please comment on this?
Is there any better alternative available?

I strongly recommend to use DTOs level, here are several reasons:
At some point your REST representation will not be matched completely to DAO Entity. Here are few examples:
You need to return full list of lightweight user info (only user first and last name) for mobile version of your app
You want to provide User info loaded from DAO + some payment account info, retrieved from separate service.
You want to combine information from two separate DAO entities into one service call
etc.
Caching of data using some 3rd party library (EhCache, Hazelcast, etc.) or simple Map like structure - Custom serialization of Hibernate entities could become a big pain for entities with complex relationships.
With DTO level you have Service Interfaces/DTOs as an interface/client library for integration with other components. And you still safe to modify/completely redesign your DAO layer implementation, even switching to No SQL solution for example.
As a conclusion - using Hibernate Entities in REST API works fine for simple "Hello World" like apps and doesn't work for most of real life solutions.

Option 1 is the best approach
Create an intermediate layer of objects (like DTOs) mimicking entity
objects
Creating DTO object will make your design more flexible, All you have to do is to handle the DTO objects within the rest Controller not in the service Layer, that way you can use the same service Layer to produce many DTO's.
Copying between entity and DTOs, it is an extra work, but you can use a Mapper to handle that like Dozer
Consider this example :
#Service
public class MyService {
#Transactional
public User getUserBId(Long id){
User user = ....
return user;
}
}
Rest Controller:
#RestController
public UserRestController {
#Resource
private Myservice service;
#Resource
private Mapper mapper;
// here you can use a dto
#RequestMapping(...)
public UserDto getUser(#RequestParam()Long userId){
User user = service.getUserBId(userId);
return mapper.map(user,UserDto.class);
}
}

In such a scenariou you should ideally be using Hibernate4Module (reference Hibernate4Module github Link)
Using this will ensure the serialization of entities to JSON on the spring rest layer respects the lazy loaded attributes and will not try access them (or serialize them to JSON in your case).
I will list out a possible solution code below.
If you are using maven, these would be your dependencies :
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate4</artifactId>
<version>2.3.0</version>
</dependency>
Create a class HibernateAwareObjectMapper and register the Hibernate4Module in it.
package com.mypackage.web;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.hibernate4.Hibernate4Module;
public class HibernateAwareObjectMapper extends ObjectMapper {
private static final long serialVersionUID = 1L;
public HibernateAwareObjectMapper() {
registerModule(new Hibernate4Module());
}
}
If you are using spring beans xml based config you could use something like below :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="...">
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.mypackage.web.HibernateAwareObjectMapper"/>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
</beans>
else in case you are using pure java based config as in Spring boot you can do it like this:
#Configuration
#EnableWebMvc
#EnableAsync
#ComponentScan(basePackages = { "com.mypackage.controller" }) // package referring to controllers
#PropertySource("classpath:imagesConfig.properties")
public class WebConfiguration
extends WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter
{
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters){
List<MediaType> supportedMediaTypes=new ArrayList<>();
supportedMediaTypes.add(MediaType.APPLICATION_JSON);
supportedMediaTypes.add(MediaType.TEXT_PLAIN);
MappingJackson2HttpMessageConverter converter=new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(new HibernateAwareObjectMapper());
converter.setPrettyPrint(true);
converter.setSupportedMediaTypes(supportedMediaTypes);
converters.add(converter);
super.configureMessageConverters(converters);
}
}
Then your controllers could look something like this:
#RequestMapping(value="/doSomething", method=RequestMethod.POST, produces="application/json;charset=UTF-8")
public #ResponseBody MyCustomWebResponseObject<MyEntity> create(#Valid #RequestBody MyEntity myEntity) throws Exception {
// do whatever
}
Also Now if you want to still pass along a lazy loaded attribute of an entity,
then in your service/DAO layer or the layer which is annotated by #Transactional
you could do this :
Hibernate.initialize(myEntity.getLazyLoadedAttribute());
I hope this helps :)
do upvote and mark this as an answer if my answer helps you :)

Related

Create new Entity Object in Spring Boot

I'm hoping someone could shed some more light on my confusion with JPA entities in a Spring Boot project. I've heard that one should never call new in a Spring project. I understand that this is to allow Spring to manage all of the beans, and getting a bean can be done through injection or through the application context explicitly.
However, it's not clear to me how to get a new JPA Entity. If I have a class annotated with #Entity and a repository class that handles my data access, how do I obtain a new entity object in my service layer?
I've included #EntityScan in my application's main class so I would assume that Spring is aware of the entity. But when I try to get it through the ApplicationContext an exception is raised. This makes sense because I don't believe the #Entity annotated classes are Spring Beans, and I don't think it would be correct to also annotate it with #Component. Any clarification would be greatly appreciated.
I'm currently using the new keyword and creating the entity objects myself in the service layer. A very simple example is below:
entities/User.java
#Entity
#Table(name = "users")
public class User {
#Id
private Long id;
private String username;
// Getters & Setters ...
}
repositories/UserRepository.java
#Repository
public interface UserRepository extends CrudRepository<User, Long> {
User findByUsername(String username);
}
services/UserServiceImpl.java
#Service
public class UserServiceImpl implements UserService {
UserRepository userRepository;
#Autowired
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
public void createAndSaveUser(String username) {
User user = new User();
user.setUsername(username);
userRepository.save(user);
}
}
And we could assume that there was some other controller classes that would utilize the service layer.
In this example I am explicitly calling the new keyword in the service class method createAndSaveUser. Is this the correct way to do it or should I be getting some prototype bean from Spring that maps to my JPA entity?
In spring you can autowire/inject your beans, components or services. However the entity should not be autowired since these interactions are done through your repository. Your repository can be autowired.
When you want to create a new instance of your entity you are allowed to call new, because this does not need to be managed by spring. You can simply use the autowired repository to save it in the database. This also works the other way around because obviously you would need the autowired repository to retrieve your entity.
So yes, your method is correct.
I hope this makes it clearer for you, if you have any questions feel free to ask :)
Whatever you are doing is completely valid in spring. In example you have provided above I could figure out that you want your entity class object itself to store the values. Its absolutely correct.
You have to use new keyword to achieve that.
If you still wish to not create a new object for your Entity you have another option to do it through Bean/POJO/VO classes and mapping your entity object with these classes.
But Still i will tell that whatever you have done is completely fine.
Actually the object you are creating is for storing value purpose not just because you have some method is there in your class and so you are bound to create new Object to be able to call that method(As we do in normal java project).In spring that is handle by #Autowired annotation to create object.
Simple example is you will be auto-wiring your repositories in your service classes.
I hope this help.
It sounds good to me: you create your entity and then ask the repository to store it.. no problem with Spring.
have you checked this out? :
http://spring.io/guides/gs/accessing-data-jpa/
have fun

Commit transaction immideatly after method finished

I have the following problem:
I'm using Spring MVC 4.0.5 with Hibernate 4.3.5 and I'm trying to create a Restfull Web application. The problem is that I want to exclude some fields from getting serialized as JSON, depending on the method called in the controller using aspects.
My problem now is that Hiberate does not commit the transaction immideatly after it returns from a method but just before serializing.
Controller.java
public class LoginController {
/*
* Autowire all the Services and stuff..
*/
#RemoveAttribues({"fieldA","fieldB"})
#RequestMapping{....}
public ResponseEntity login(#RequestBody user) {
User updatedUser = userService.loginTheUser(user);
return new ResponseEntity<>(updatedUser,HttpStatus.OK);
}
}
Service.java
public class UserService {
#Transactional
public User loginUser(User user) {
user.setLoginToken("some generated token");
return userDao.update(user); //userDao just calls entityManager.merge(..)
}
}
The advice of the aspect does the following:
for every String find the corresponding setter and set the field to null
This is done, like I said, to avoid serialization of data (for which Jackson 2 is used)
The problem now is that only after the advice has finished the transaction is commited. Is there anything I can do to tell hibernate to commit immediatly or do I have to dig deeper and start handling the transactions myself (which I would like to avoid)?
EDIT:
I also have autocommit turned on
<prop key="hibernate.connection.autocommit">true</prop>
I think the problem lies in the fact that I use lazy loading (because each user may have a huge laod of other enities attached to him), so the transaction is not commited until I try to serialze the object.
Don't set auto-commit to true. It's a terrible mistake.
I think you need a UserService interface and a UserServiceImpl for the interface implementation. Whatever you now have in the UserService class must be migrated to UserServiceImpl instead.
This can ensure that the #Transactions are applied even for JDK dynamic proxies and not just for CGLIB runtime proxies.
If you are using Open-Session-in-View anti-patterns, you need to let it go and use session-per-request instead. It's much more scalable and it forces you to handle optimum queries sin your data layer.
Using JDBC Transaction Management and the default session-close-on-request pattern you should be fine with this issue.

Spring AOP and Spring JPA, Aspect to be executed

I have been writing an aspect that manipulates some of my JPA entities getters. It is supposed to re-format the returned text based on the clients locale. Because not all of my getters should be reformatted I introduced an annotation #ReFormat.
The problem is my aspect is never intercepted when I advise it to an JPA entity but it works fine on non JPA entities (it works when I create my own entity object via a copy constructor).
My annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE})
public #interface ReFormat {
}
My aspect:
#Aspect
public class ReFormatAspect {
#AfterReturning(pointcut = "#annotation(com.path.ReFormat)", returning = "response")
public Object formatter(JoinPoint joinPoint, Object response) {
return response;
}
}
Now this aspect is intercepted successfully within my MVC controllers (or at any other place except spring data) but not for my entities.
#Entity
#Table(name = "place", schema = "db")
public class TestEntity {
#Id
#Column(name = "id")
protected long id;
#Column(name = "about", columnDefinition = "TEXT DEFAULT NULL")
protected String about;
#ReFormat
public String getAbout() {
return this.about;
}
}
I expected a point cut once the getAbout method is called, but it does not work.
Given the facts above I suppose that JPA (Hibernate) is overriding any interceptor may be by CGLib or javassist.
Note: I have this inside my context
<context:annotation-config />
<context:spring-configured />
<aop:aspectj-autoproxy proxy-target-class="true" />
So what is the exact issue, and how do I intercept any method inside an entity?
I understand this should be the view layer work, but still I need to know why :D
Your Entities are not managed by Spring, they are managed by the underlying JPA implementation. Because of this, Spring cannot wrap them in proxies and provide the wanted behavior.
There's no Spring way to solve this. Hibernate might have some interceptor tool for that (that wraps entities as they are created) but I don't know it. Maybe extending EmptyInterceptor.
You can always use AspectJ and wave your aspect in compile time. But this way you will not have an access to spring DI container.
It is possible to use AspectJ aspects together with the Spring DI container. The Spring AOP documentation sais:
Domain objects often fall into this category because they are often created programmatically using the new operator, or by an ORM tool as a result of a database query.
I created a GitHub project where I use your #ReFormat annotation on a method of a bean annotated with #Entity. In order to be able to use DI within your AspectJ aspect you need to use the aspectOf() approach. This is even possible with JavaConfig. So you don't have to use XML configuration at all.

JPA Transactions and REST Services : Good practices

I am writing an application providing REST services (with Apache-CXF) that manage JPA entities (with Hibernate).
I am a bit lost with Transaction management and would like your advice on this topic.
For now, I have put an intermediate layer between my business REST services and the lower services, solely for transaction management purpose.
Currently, my code looks much like that :
#Service
class PersistanceService<MyBusinessClass>{
MyBusinessClass load(Long id);
void save(MyBusinessClass businessObject);
}
#Service
class BusinessService<MyBusinessClass>{
void doSomethingOn(MyBusinessClass businessObject);
}
#Service
class TransactionBusinessService<MyBusinessClass>{
#Transactional
void doSomethingOn(Long id) {
MyBusinessClass businessObject = persistanceService.load(id);
businessService.doSomethingOn(businessObject);
persistanceService.save(businessObject);
}
}
#Service
#path("/foo")
class RESTService {
#Path("/doSomething")
void doSomethingOn(Long id) {
transactionBusinessService.doSomethingOn(id);
}
}
I think the TransactionBusinessService is overkill. I would like ''Spring'' or ''CXF'' to handle transactions for me : I feel that a request is the good granularity to do so : Init an entity manager at the beginning of each request, and commit updates at the end.
I've tried to add the #Transactional annotation to the REST methods themselves, but it seem to be ignored, or to conflict with CXF.
Do you think it is a good idea to delegate the transaction at the request level and not to bother about it anymore ?
How can I have Spring or CXF bind the transaction management to the requests for me ?
Thanks in advance for you advice.
Do you think it is a good idea to delegate the transaction at the request level and not to bother about it anymore ?
Usually it's not good idea, because:
usually it's not that convenient to separate Transaction isolation
if you need to do some changes in for-loop, each of which has to have own transaction, it's also not
that transparent; meanwhile on service layer you may decide whether you need the whole loop to be transactional or each of iteration;
tx:annotation-driven (and some other AOP-interceptor) sometimes works a bit unpredictable, if you are using AOP annotations in the controllers directly (at least I faced such issues in Spring MVC/struts2 and some other frameworks)
So basically, you have 3 layers:
persistence layer, which is responsible for storing/fetching data only;
service layer, which is responsible for data preparation and for AOP-annotations (#Transactional, #PreAuthorize, #Cacheable and so on), which use persistence layer within;
controller level, which gets request, binds business models, probably validates it, pass model(s) to service layer and returns result from there or handles exception
How can I have Spring or CXF bind the transaction management to the requests for me?
Please make sure, that you:
you have appropriate TransactionManager ('org.springframework.transaction.PlatformTransactionManager` implementation) in your config
you have tx:annotation-driven in your config
those beans are visible in the config of your CXF services
<bean name="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="txManager"/>

How does Spring Data JPA differ from Hibernate for large projects?

I am having a hard time deciding if I should stick with Hibernate for a new project, or get my feet wet with JPA and the new Spring Data implementation.
Is the Spring Data framework intended for large projects or small projects with modest query requirements?
While I certainly see the advantage in code reduction by using the #Query annotation, what do you do for dynamic queries? What about when you want to implement a save() method that's quite complex?
The documentation says to make a Custom interface and implementation that your main repository implements, but what if you need to access any super methods on the crud repository itself? The crud repository implements the custom one - not the other way around. It seems like an odd design.
I am very uncertain whether this framework will meet the challenges of complex and large applications. I've never ran into many problems with Hibernate, and I'm considering sticking with the good old reliable rather than go with Spring Data JPA.
What should I do? What unforeseen complications and costs will I encounter if I go with Spring Data JPA?
So, spring-data does some extra magic that helps with complex queries. It is strange at first and you totally skip it in the docs but it is really powerful and useful.
It involves creating a custom Repository and a custom `RepositoryImpl' and telling Spring where to find it. Here is an example:
Configuration class - point to your still-needed xml config with annotation pointing to your repositories package (it looks for *Impl classes automatically now):
#Configuration
#EnableJpaRepositories(basePackages = {"com.examples.repositories"})
#EnableTransactionManagement
public class MyConfiguration {
}
jpa-repositories.xml - tell Spring where to find your repositories. Also tell Spring to look for custom repositories with the CustomImpl file name:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<jpa:repositories base-package="com.example.repositories" repository-impl-postfix="CustomImpl" />
</beans>
MyObjectRepository - this is where you can put annotated and unannotated query methods. Note how this repository interface extends the Custom one:
#Transactional
public interface MyObjectRepository extends JpaRepository<MyObject, Integer>, MyObjectRepositoryCustom {
List<MyObject> findByName(String name);
#Query("select * from my_object where name = ?0 or middle_name = ?0")
List<MyObject> findByFirstNameOrMiddleName(String name);
}
MyObjectRepositoryCustom - repository methods that are more complex and cannot be handled with a simple query or an annotation:
public interface MyObjectRepositoryCustom {
List<MyObject> findByNameWithWeirdOrdering(String name);
}
MyObjectRepositoryCustomImpl - where you actually implement those methods with an autowired EntityManager:
public class MyObjectRepositoryCustomImpl implements MyObjectRepositoryCustom {
#Autowired
private EntityManager entityManager;
public final List<MyObject> findByNameWithWeirdOrdering(String name) {
Query query = query(where("name").is(name));
query.sort().on("whatever", Order.ASC);
return entityManager.find(query, MyObject.class);
}
}
Amazingly, this all comes together and methods from both interfaces (and the CRUD interface, you implement) all show up when you do:
myObjectRepository.
You will see:
myObjectRepository.save()
myObjectRepository.findAll()
myObjectRepository.findByName()
myObjectRepository.findByFirstNameOrMiddleName()
myObjectRepository.findByNameWithWeirdOrdering()
It really does work. And you get one interface for querying. spring-data really is ready for a large application. And the more queries you can push into simple or annotation only the better off you are.
All of this is documented at the Spring Data Jpa site.
I've used Spring Data JPA in small and large projects with simple query demands. The main advantage is from not even having to use the #Query annotation. There is nothing in Spring Data that prevents you from using it in large projects and the recent QueryDSLsupport might help you. This is an example of using QueryDSL to target Hibernate.
If you foresee complex queries and you feel comfortable using Hibernate objects without JPA I think an alternative combination could be to have the simple Spring Data Repositorys next to complex Hibernate-based ones with the specific methods you might need. It might be less cumbersome that twisting a Hibernate implementation into Spring Data JPA structure.
Spring JPA will provide you a lot of abstraction from writing SQL and even some HQL using query method declaration. Spring JPA shines with its query generation but when you want a purely hibernate solution you can customize as needed as spring JPA is still based on hibernate. Check the docs http://static.springsource.org/spring-data/data-jpa/docs/current/reference/html for more info.

Categories

Resources