How to avoid lazy fetch in JSON serialization using Spring Data JPA + Spring Web MVC? - spring

I have a solution using Spring Data JPA and a REST Controller in Spring Web MVC. The persistence provider is Hibernate.
The persistence layer is built using Spring Repositories and between de REST Controller and the repository exists a Service Layer:
Entity <--> Repository <--> Service <--> Controller
At entity level, I have #OneToMany fields with FetchType = LAZY.
When the REST Controller make the serialization, the fetching is made, but this is undesirable in some cases.
I already tried with #JSONInclude Jackson annotation and the serialization still occurs.
Can somebody help me with a proved solution?

If I understood you properly, you want to serialize only when the lazy loaded collection is fetched, but you don't want the serialization to trigger the fetching.
If that is the case you should use the jackson-datatype-hibernate, and added as their docs already explains
public class HibernateAwareObjectMapper extends ObjectMapper {
public HibernateAwareObjectMapper() {
registerModule(new Hibernate4Module());
}
}
than register
<mvc:annotation-driven>
<mvc:message-converters>
<!-- Use the HibernateAware mapper instead of the default -->
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="path.to.your.HibernateAwareObjectMapper" />
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
The module has a Feature.FORCE_LAZY_LOADING settings, that tells whether the object should be forced to be loaded and then serialized, which is by default set to false which I believe is the behaviour you need

Simple architectural solution is not to use model Entity as Data Transfer Object. Make Simple POJO as Data transfer Object. In the conversion logic you could easily put try and catch block for LazyInitializationException. And thus your POJO is always serializable and You can use it on your controller.

Use the #JsonIgnore annotation if you ALWAYS want to skip this particular field. use #JsonView if you want to dynamically determine which field(s) to skip. Note that #JsonView is a Jackson specific annotation, but since you're already using Jackson, things should be fine.

We can do this by adding Hibernate4Module (which support Lazy objects) to the default MappingJackson2HttpMessageConverter that Spring already provide and by adding it to HttpMessageConverters.
So we need to extend our spring config class from WebMvcConfigurerAdapter and override the method configureMessageConverters and add MappingJackson2HttpMessageConverter with the Hibernate4Module registered in it.
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
//Here we add our custom-configured HttpMessageConverter
converters.add(jacksonMessageConverter());
super.configureMessageConverters(converters);
}
// Here we register the Hibernate4Module into an ObjectMapper,
// then use this custom ObjectMapper
// to the MessageConverter
public MappingJackson2HttpMessageConverter jacksonMessageConverter(){
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper mapper = new ObjectMapper();
//Registering Hibernate4Module to support lazy objects
mapper.registerModule(new Hibernate4Module());
messageConverter.setObjectMapper(mapper);
return messageConverter;
}

You can solve this problem with wit 2 steps with jackson-datatype-hibernate:
kotlin example
Add In build.gradle.kts:
implementation("com.fasterxml.jackson.datatype:jackson-datatype-hibernate5:$jacksonHibernate")
Create #Bean
#Bean
fun hibernate5Module(): Module = Hibernate5Module()
Notice that Module is com.fasterxml.jackson.databind.Module, not java.util.Module
Also good practice is to add #JsonBackReference & #JsonManagedReference to #OneToMany & #ManyToOne relationships.

Related

Spring 4.1's JsonView and Hibernate4Module

I have a project which liberally uses lazy loading via the org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter view filter.
If I disable this, I have to add a new message converter in my rest servlet configuration:
public MappingJackson2HttpMessageConverter jacksonMessageConverter() {
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper mapper = new ObjectMapper();
// Registering Hibernate4Module to support lazy objects
mapper.registerModule(new Hibernate4Module());
messageConverter.setObjectMapper(mapper);
return messageConverter;
}
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
// Add the custom-configured HttpMessageConverter
converters.add(jacksonMessageConverter());
super.configureMessageConverters(converters);
}
However, doing so seems to break the behavior of #JsonView: the existence of the #JsonView annotation no longer seems to filter in/out any properties.
My guess is Hibernate4Module doesn't support #JsonView, but if that's the case, how can I use Spring 4.1's #JsonView support and make Jackson cognizant of lazy-loaded Hibernate entities? The only solution so far seems to be avoiding Hibernate4Module and relying on the OpenEntityManagerInViewFilter filter.
Thanks for any insight you can offer.
Whenever you are using spring 4.1.*, make sure you are changing
import org.codehaus.jackson.annotate.*;
to
import org.fasterxml.jackson.annotate.*;
in your case its
import org.fasterxml.jackson.annotate.JsonView;
I think you need to configure the DEFAULT_VIEW_INCLUSION feature to be false. By default all properties without explicit view definition are included in serialization. Out of box Spring will disable this default for you. So if you want to use your own custom mapper you will probably want to disable it or all the properties with out #JsonView annotations will get added to you JSON.
mapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);

Spring and jackson, how to disable FAIL_ON_EMPTY_BEANS through #ResponseBody

Is there a global configuration in spring that can disable spring FAIL_ON_EMPTY_BEANS for all controller annotated with #ResponseBody?
If you are using Spring Boot, you can set the following property in application.properties file.
spring.jackson.serialization.FAIL_ON_EMPTY_BEANS=false
Thanks to #DKroot for his valuable comment. But I believe this should be its own answer for others.
You can configure your object mapper when configuring configureMessageConverters
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
MappingJackson2HttpMessageConverter converter =
new MappingJackson2HttpMessageConverter(mapper);
return converter;
}
If you want to know how to do exactly in your application, please update your question with your configuration files (xml or java configs).
Here is a good article how to customize message converters.
Edit: If you are using XML instead of Java configs, you can create a custom MyJsonMapper class extending ObjectMapper with custom configuration, and then use it as follows
public class MyJsonMapper extends ObjectMapper {
public MyJsonMapper() {
this.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
}
}
In your XML:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="jacksonObjectMapper" class="com.mycompany.example.MyJsonMapper" >
cant find spring.jackson.serialization.FAIL_ON_EMPTY_BEANS=false in spring boot 2.2.5
I use this
#Configuration
public class SerializationConfiguration {
#Bean
public ObjectMapper objectMapper() {
return new ObjectMapper().disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
}
}
If you are using Spring Boot / JPA , you also have to observe if you are using
getOne (goes for jpa getReference ) for the findOne / enetiyManager.find(Clazz , id)
GetOne Relies on Persistence cached reference by ID that is designed to retrieve entity with only ID in it. Its use was mostly for indicating reference existed without the need to retrieve whole entity.
The find method is straight forward to persistence manager to obtain the persistent instance.
This second one will observe you annotation #JsonIgnore accordingly and will give you the expected result.
// On entity...
#JsonIgnore
#OneToMany(fetch = FetchType.LAZY, mappedBy = "foo")
private List<Foo> fooCollection;
// later on persistence impl
entityManager.find(Caso.class, id);
// or on serivce
casoRepository.findById(id); //...
For me, the Issue was with typecasting from org.json.JSONObject object to org.json.simple.JSONObject and I solved it by parsing value from org.json.JSONObject and then cast it to use as org.json.simple.JSONObject
JSONParser parser = new JSONParser();
org.json.simple.JSONObject xmlNodeObj = (org.json.simple.JSONObject) parser.parse(XMLRESPONSE.getJSONObject("xmlNode").toString());

Spring and manually created DAOs how to refactor to enable hasPermisions on such DAOs objects

I have got Dao implentation like this
public class EntityDao<T> {
private Class clazz;
private SessionFactory sessFactory;
public EntityDao(Class clazz, SessionFactory sessFactory) {
this.clazz = clazz;
this.sessFactory = sessFactory;
}
.... dao methods
}
and factory for retriving and storing particular dao
EntityBeanDaoFactory {
private HashMap<EntityDaoType, EntityDao> daoMap = new HashMap<EntityDaoType, EntityDao>();
// return dao from daoMap if exists a if not create it and put it in the map then return dao
public EntityDao createDao(EntityDaoType entityType) {
switch (entityType) {
case mySpecialDaoTYPE:
if (!daoMap.containsKey(entityType)) {
EntityDao<Type> mySpecialDao = new EntityDao(Type.class, sessFactory);
daoMap.put(entityType, mySpecialDao);
}
return daoMap.get(entityType);
}
}
now I want to annotate dao methods with #PreAuthorize("hasPermission()") but spring doesn't know about daos created this way and I am not able to refactor whole project at once so I have created dao ,on wich I need to use the annotation, inside aplicationContectxt.xml
<bean id="mySpecialDao" class="..EntityDao" >
<constructor-arg>
<value>myClass</value>
</constructor-arg>
<constructor-arg ref="sessionFactory" />
</bean>
inside the factory I have changet behavior for creating this particular dao like this
if (!daoMap.containsKey(entityType)) {
EntityDao<Class> dao = (EntityDao<Class>) AppContext.getApplicationContext().getBean("mySpecialDao");
daoMap.put(entityType, dao);
}
is there some better way how to make spring aware of my DAOs ? I mean is there way how to make Spring aware of manualy created instancess ?
You could do this using Spring AOP support using AspectJ. Read more here: http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/aop.html#aop-atconfigurable
After enabling this, Spring would be aware of any instances created of classes annotated with the Configurable annotation. Spring would then be able to recognize the PreAuthorize annotations.
Why do you need a factory to create DAOs? That's what the Spring application context is.
You look like you want to restrict the ability to call DAO methods using role based security. I think that's fine, and possible to do, but you need not restrict creation of the DAO. Create it using Spring and then restrict access. Your way is overkill and unnecessary.

Spring beginner questions about annotations and thread safety

I am not sure if I am allowed to ask more than one question in a post, but here it is,
For example I have the following,
Controllers
#Controller
public class FooController{
#Autowired
private FooService fooService;
#RequestMapping(value="/foo", method=RequestMethod.POST)
public #ResponseBody foo(#RequestBody FooRequest request){
}
}
#Controller
public class BarController{
#Autowired
private FooService fooService;
#RequestMapping(value="/bar", method=RequestMethod.POST)
public #ResponseBody bar(#RequestBody FooRequest request){
}
}
Service
public class FooService{
private Foo foo;
public Foo getFoo() {
return foo;
}
public void setFoo(Foo foo) {
this.foo = foo;
}
public String doFoo(String str){
return foo.doFoo(str);
}
}
class to do the job
public class Foo{
public String doFoo(String str){
return (str + " is foo");
}
}
create beans using dependency injection
<context:annotation-config/>
<bean id="fooService" class="com.myapp.service.FooService">
<property name="foo" ref="foo"></property>
</bean>
<bean id="foo" class="com.myapp.foo.Foo">
</bean>
My questions are:
I did not use #service annotation at class FooService, should I use it, and why?
Is this configuration thread-safe or not, and why (how is it achieved if it is thread-safe)?
Where can I find a tutorial about the layers (dao layers, service layer ...) used in Spring design and the purpose of such a design?
You don't have to use annotations if you declare your beans in xml-config, as you did.
It is. Each bean, although a singleton, is stateless. So no concurrent modifications can occur.
For example in wikipedia. It's not spring-specific. Look for articles about three-tier architecture
Using it would simply avoid the need for declaring the bean using XML. You chose to use annotations for your other beans. I would thus also use annotations for this one.
Yes, it is, because Spring makes sure everything is properly wired up and initialized, with a synchronization barrier, before serving any request
This is a very broad question. Layering is useful for separation of concerns, testability, ability to demarcate transactions declaratively, etc.
#Repository, #Service, or #Controller (sub-annotations of #Components) are used to mark specific classes, so they can be considered more-or-less as metadata. However, there are some features of the Spring framework that can take advantage of these. One of them is automatic component scanning (a given java package will be searched for classes with the above annotations and these classes can be used as Spring beans, as if they were declared in XML). To enable this, you should put this into your spring context:
<context:component-scan base-package="my.service.package"/>
More on this can be found here: http://static.springsource.org/spring/docs/3.0.x/reference/beans.html#beans-classpath-scanning
Another use-case is for AOP. You can create annotation-aware pointcuts by which you can select say all your repository classes.
The Spring beans in context are brought up one by one, so there is no chance of concurrency kicking in. However, there can be circular dependencies between beans and Spring may or may not resolve this properly.
For both DAO and service stuff, the current Spring 3 documentation provides many examples and probably the best source for learning: http://static.springsource.org/spring/docs/3.0.x/reference/index.html If you'd like to have an all-round knowledge I'd recommend trying out JdbcTemplate, Rowmappers and an ORM based configuration with Hibernate.

Dynamically load spring bean properties from database or Java Objects )

I have a scenario where I need to load properties from database or java object into beans.
Consider the example:
<bean id="ConfigAsstDemoBeanParent" class="gps.springconfig.DemoClass" lazy-init="true">
<property name="demoValueFromBean" value="demoValue"></property>
<property name="demoValueForKeyFromProperties" value="${DEMO_KEY}"></property>
</bean>
and instead of the ${DEMO_KEY} property placeholder, which loads a value from the property file, I need to load a value from the database, which I retrieve using a stored procedure from a Java class.
Please suggest me a mechanism which I can leverage for the above scenario. Currently I am investigating extending SpringMain and/or PropertyPlaceholderConfigurer class and write my own custom BootStrapper.
Also please suggest hints on writing a BootStrapper for the above mentioned scenario.
One of the cases where Java configuration seems to be a great alternative:
#Configuration
public class Config {
#Resource
private DataSource dataSource;
#Bean
#Lazy
public DemoClass configAsstDemoBeanParent() {
DemoClass demo = new DemoClass();
demo.setDemoValueFromBean("demoValue");
demo.demoValueForKeyFromProperties( /* query the database here */);
return demo;
}
}
Note that you can inject DataSource (or JdbcTemplate) to your #Configuration class providing it was defined elsewhere.

Resources