Spring Data Rest: Entity serialization with LAZY object cause JsonMappingException - spring-mvc

I'm getting the following Exception with a Spring Data Rest project:
com.fasterxml.jackson.databind.JsonMappingException:
No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer
(to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) )
(through reference chain: org.springframework.data.rest.webmvc.json.["content"]->test.spring.data.rest.xml.entities.Author_$$_jvstb93_1["handler"])
Certainly, I have some entities that have the fetch configuration = FetchType.LAZY.
I followed many instructions and links, but I still have this exception.
What I have already tried to do (with NO effetcs):
add #EnableHypermediaSupport(type = HypermediaType.HAL) in a config class that extends RepositoryRestMvcConfiguration
#Override configureJacksonObjectMapper in the same class, with also using Jackson2DatatypeHelper.configureObjectMapper():
#Override
protected void configureJacksonObjectMapper(ObjectMapper objectMapper) {
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
Jackson2DatatypeHelper.configureObjectMapper(objectMapper);
}
add a "org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter" filter in the web.xml
create a custom class that extends ObjectMapper, with this constructor:
public HibernateAwareObjectMapper() {
Hibernate5Module hm = new Hibernate5Module();
registerModule(hm);
}
and this config:
<mvc:annotation-driven>
<mvc:message-converters>
<bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="test.spring.data.rest.xml.config.HibernateAwareObjectMapper" />
</property>
</bean>
</mvc:message-converters>
No one of the actions above has solved the problem!
How to (definitely) solve this problem?
Thanks.

I have found the solution to this annoying problem.
For every repository of the Spring Data Rest application it has to be defined a custom #Projection; in the projection there will be the necessaries fields.
Pay attention that if there are cycylc references between two entities, the corrispective methods of the projections have to be annotated with #JsonBackReference annotation (for #ManyToOne annotated fields) and with #JsonManagedReference annotation (for #OneToMany annotated fields), otherwise there will be a JSON loop in the JSON serialization.
In every #Repository annotation (or #RepositoryRestResource annotation) it has to be marked the excerptProjection property, with the custom projection.
With this management, there is no need of any other configuration, and the exception for Lazy objects finally is vanished.

Related

Customizing Hybris accelerator storefront controllers in an addon

I'm using Hybris 6.3 and would like to follow the best practice of customizing the accelerator storefront controllers using an addon. This is done to make upgrading to a newer storefront much easier.
For example, the accelerator defines a Minicart controller similar to
package com.custom.storefront.controllers.misc;
#Controller
public class MiniCartController extends AbstractController
{
#RequestMapping(value = "/cart/miniCart/{totalDisplay:.*}", method = RequestMethod.GET)
public String getMiniCart(#PathVariable final String totalDisplay, final Model model)
{
//default functionality
}
}
In my addon, I would like to map that same URL pattern to a new controller that will override the functionality.
package com.custom.storefrontaddon.controllers.misc;
#Controller
public class MyCustomMiniCartController extends AbstractController
{
#RequestMapping(value = "/cart/miniCart/{totalDisplay:.*}", method = RequestMethod.GET)
public String getMiniCart(#PathVariable final String totalDisplay, final Model model)
{
//overriding functionality, different from the default accelerator storefront
}
}
This question has been asked here, and the accepted advice was to do as follows:
In addon-web-spring.xml, override the controller bean like
<bean name="miniCartController" class="com.custom.storefrontaddon.controllers.misc.MyCustomMiniCartController"/>
In addon-web-spring.xml, add a SimpleUrlHandlerMapping like
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/cart/miniCart/**">miniCartController</prop>
</props>
</property>
</bean>
The addon controller will now be called instead of the default accelerator controller for the target URL.
My Question
How does this mechanism work when the Spring documentation explicitly says that
There are also several things no longer possible:
- Select a controller first with a SimpleUrlHandlerMapping or BeanNameUrlHandlerMapping and then narrow the method based on #RequestMapping annotations.
Spring is using RequestMappingHandlerMapping by default in the accelerator storefront, and in the addon we are introducing SimpleUrlHandlerMapping. I want to understand why this works, when every other forum post I've read says that you cannot override #RequestMapping URLs in a different controller, or you will get an exception thrown for the duplicate URL.
In my answer, I will suppopse that you made a typo, and you meant MyCustomMiniCartController instead of MiniCartController in:
<bean name="miniCartController" class="com.custom.storefrontaddon.controllers.misc.MyCustomMiniCartController"/>
The thing here is that SimpleUrlHandlerMapping has nothing to do and its declaration in
addon-web-spring.xml is completely useless.
Redefining the miniCartController bean in the addon makes the bean definition overridden by the addon class, and so the request mapping that is declared in the addon class is the one "used" by the RequestMappingHandlerMapping.

Spring Web Flow Conversion Service in JavaConfig

I've started working on a web application in Spring Weblow. The idea is to write as much as possible in Java, rather than XML. So I started off with a JavaConfig file for both the MVC configuration and the Web Flow configuration. But I ran into a problem when needing converters for entering and submitting a form with Spring Web Flow.
I did a lot of research on ConversionService and Converters. I found plenty examples of implementing a custom ConversionService and custom Converters, but I found no examples to to add the ConversionService to the Web Flow configuration in JavaConfig (configuration was always XML).
I did try to reproduce the XML config in Java, which nearly worked. In a form page, a list of POJOs (Employee) was represented as a dropdownlist. The input was List<Employee> and the converter (subclass of StringToObject) worked to represent each Employee as a String. But when submitting the form, I got the error that no converter was found for String to Employee. So basically, the custom converter was found and used when rendering the page, but when submitting the form, the same converter could not be found for the reverse process.
I eventually got it fixed by rolling the JavaConfig back to XML config and adding a custom Formatter to the ConversionService of the MVC config. But I'd like to make this work in JavaConfig if it is at all possible.
I believe the problem is that a ConversionService bean (org.springframework.core.convert package) needs to be added to the MVC config, because this bean needs to be set as a delegate ConversionService in the ConversionService bean to be added to the Web Flow Config (the latter from the org.springframework.binding.convert package). But I don't know how to add this core ConversionService in JavaConfig like in the mvc:annotation-driven tag in the code below.
It all boils down to needing the JavaConfig version of the following code:
<mvc:annotation-driven conversion-service="typeConversionService" ... />
<bean id="typeConversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<list>
<bean class="some.package.holidays.formatter.EmployeeFormatter">
<constructor-arg ref="employeeService"/>
</bean>
<bean class="org.springframework.format.datetime.DateFormatter">
<constructor-arg value="dd/MM/yyyy"/>
</bean>
</list>
</property>
</bean>
If anyone would know about JavaConfig for Spring Webflow, especially about adding a ConversionService, please let me know, it would be a great help.
I had the same thing to do in a project and this is how I did it. I know it might be late for you, but maybe somebody else needs the answer to this:
#Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {
#Autowired
private MvcConfig webMvcConfig;
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder()
.setViewFactoryCreator(mvcViewFactoryCreator())
.setValidator(this.webMvcConfig.validator())
.setConversionService(conversionService())
.setDevelopmentMode(true)
.build();
}
#Bean
DefaultConversionService conversionService() {
return new DefaultConversionService(conversionServiceFactoryBean().getObject());
}
#Bean
FormattingConversionServiceFactoryBean conversionServiceFactoryBean() {
FormattingConversionServiceFactoryBean fcs = new FormattingConversionServiceFactoryBean();
Set<Formatter> fmts = new HashSet<>();
fmts.add(this.webMvcConfig.dateFormatter());
fmts.add(this.webMvcConfig.employeeFormatter());
fcs.setFormatters(fmts);
return fcs;
} }
I upvoted the accepted answer but would also like to add this. I kept getting the below error.
'conversionService': Requested bean is currently in creation: Is there an unresolvable circular reference?
To fix this, remove conversionService bean like this. (note the setConversionService difference).
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder()
.setViewFactoryCreator(mvcViewFactoryCreator())
.setValidator(localValidatorFactoryBean)
.setConversionService(new DefaultConversionService(conversionServiceFactoryBean().getObject()))
.setDevelopmentMode(true)
.build();
}
#Bean
FormattingConversionServiceFactoryBean conversionServiceFactoryBean() {
FormattingConversionServiceFactoryBean fcs = new FormattingConversionServiceFactoryBean();
Set<Formatter> fmts = new HashSet<>();
fmts.add(this.webMvcConfig.dateFormatter());
fmts.add(this.webMvcConfig.employeeFormatter());
fcs.setFormatters(fmts);
return fcs;
}

Run-Time Configuring a Hibernate Validation Annotation

I have some business validation logic of the form "X is valid IFF Service Y returns Z", where X and Z are known at compile time, and Y's location is loaded from a Spring configuration file.
I'd like to use JSR-303 annotation-based validation, together with the Spring config, so I can write code like the following:
Custom class level constraint annotation:
#MyValidation
public class X { .... }
ConstraintValidator for #MyValidation:
public class MyValidationValidator implements ConstraintValidator<MyValidation, X> {
private MyService service;
public MyService getService() { return service; }
public void setService(MyService serv) { this.service = serv; }
//Validation Logic...
}
Spring config:
<bean id="ServiceY" class="...">
...
</bean>
<bean id="mvv" class="MyValidationValidator">
<property name="service" value="ServiceY" />
</bean>
But my attempts at combining these in that fashion are failing, as the validator's property is not getting set.
Right now, I'm using Spring AOP Interceptors as a workaround, but that's not ideal in my mind.
One of the other questions here, made me think of using a properties file/property, but wouldn't that require me to repeat the service's configuration?
Another mentioned defining the constraint mapping programmatically, but if I'm doing that, I'm probably better-off with my workaround.
Any clues on how to do that dynamic configuration?
You should use Spring's LocalValidatorFactoryBean to set up a Bean Validation validator:
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
A validator set up that way will internally use a ConstraintValidatorFactoryimplementation that performs dependency injection on the created validator instances, just mark the service field in your validator with #Inject or #Autowired. Note that it's not required to set up the constraint validator itself as Spring bean.
You can find more details in the Spring reference guide.

creating and access properties file in spring mvc

read this article on SO, and had some clarifying questions.
I put my config.properties under src/main/resources
In spring-servlet.xml config file
I added the following:
<context:property-placeholder location="classpath:config.properties"/>
In my business layer, I am trying to access it via
#Value("${upload.file.path}")
private String uploadFilePath;
Eclipse shows error:
The attribute value is undefined for the annotation type Value
Can i not access the property in the business layer or are property files only read in the controller?
UPDATE::
src/main/java/com.companyname.controllers/homecontroller.java
public String home(Locale locale, Model model) {
MyServiceObject myObj = new MyServiceObject();
System.out.println("Property from my service object: = " + myObj.PropertyValue());
if(myObj.PerformService())
{
///
}
}
src/main/java/com.companyname.services/MyService.java
public class MyServiceObject {
#Value("${db.server.ip}")
private String _dbServerIP;
public String PropertyValue() {
return _dbServerIPaseURL;
}
}
Another site where I found the explanation
Please check that you import Value from org.springframework.beans.factory.annotation package:
import org.springframework.beans.factory.annotation.Value;
also the property placeholder must be declared in the respective context configuration file, in case of controller it's likely Spring dispatcher servlet configuration file.
update You are confusing property-placeholder that post processes bean values, that contain dollar symbol ${<property name>} with Spring expression language container extension that process values containing a hash symbol #{<Spring expression language expression>}, in the link you have shown the latter approach is used.
regarding the instantiation of MyServiceObject myObj
If you want the object to be managed by Spring you should delegate its creation to the container:
if MyServiceObject is a stateless service then it's a singleton with the singleton bean scope, you should register it in your application context, for example with the following xml configuration:
<bean class="my.package.MyServiceObject"/>
and inject it to your controller:
private MyServiceObject myServiceObject;
#Autowired
public void setMyServiceObject(MyServiceObject myServiceObject){
this.myServiceObject = myServiceObject;
}
if many instances of MyServiceObject are required, you can declare it as a bean with some other (non-singleton) bean scope (prototype, or request, for example).
However, as there's only one instance of the controller, you can't merely let the Spring container to autowire MyServiceObject instance to the controller field, because there will be only one field and many instances of MyServiceObject class. You can read about the different approaches(for the different bean scopes) for resolving this issue in the respective section of the documentation.
Here is a method that allows us to fetch whatever values are needed from a property file. This can be in Java code (Controller class) or in a JSP.
Create a property file WEB-INF/classes/messageSource.properties It will be in the classpath and accessible in both controllers and JSTL.
Like any property file, this one consists of a key and a value
For example:
hello=Hello JSTL, Hello Contoller
For the Controllers
Locate the xml file that you use to define your Spring beans. In my case it is named servlet-context.xml. You may need to determine that by looking in your web.xml in cases where you are using the servlet contextConfigLocation property.
Add a new Spring bean definition with the id="messageSource". This bean will be loaded at runtime by Spring with the property file key value pairs. Create the bean with the following properties:
bean id="messageSource"
class = org.springframework.context.support.ReloadableResourceBundleMessageSource
property name="basename" value="WEB-INF/classes/messageSource
In the bean definition file for the controller class (testController) add the messageSource as a property. This will inject the messageSource bean into the controller.
bean id="testController" class="com.app.springhr.TestController"
beans:property name="messageSource" ref="messageSource"
In the controller JAVA class, add the messageSource Spring Bean field and its getters and setters. Note the field type is ReloadableResourceBundleMessageSource.
private org.springframework.context.support.ReloadableResourceBundleMessageSource messageSource;
public org.springframework.context.support.ReloadableResourceBundleMessageSource getMessageSource() {
return messageSource;
}
public void setMessageSource(
org.springframework.context.support.ReloadableResourceBundleMessageSource messageSource) {
this.messageSource = messageSource;
}
In your controller code, you can now fetch any known property value from the bundle.
String propValue = getMessageSource().getMessage("hello", objArray, null);
Using JSTL
Since the property file messageSource.properties is in the classpath, JSTL will be able to find it and fetch the value for the given key.
Add the import of the fmt taglib
taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"
Use the fmt:tag in the JSP to fetch a value from the property file.
Sorry about the pseudo syntax, this editor doesn't seem to render any XML.
fmt:bundle basename="messageSource"
fmt:message key="hello"
Hope this helps others

Externalize #InitBinder initialization into WebBindingInitializer

There are two major means of data binding initialization, but there is a drawback in the oldschool one, that I can't figure out. This annotation way is great :
#InitBinder("order")
public void initBinder(WebDataBinder binder) {
// Problem is that I want to set allowed and restricted fields - can be done here
binder.setAllowedFields(allowedFields.split(","));
}
but I can't be done with ConfigurableWebBindingInitializer. First off, the binder instance is created in AnnotationMethodHandlerAdapter and initializer is passed the binder instance somewhere in HandlerMethodInvoker so I can't set it up... I can't do something like this :
<bean id="codesResolver" class="org.springframework.validation.DefaultMessageCodesResolver" />
<bean id="binder" class="org.springframework.web.portlet.bind.PortletRequestDataBinder" scope="prototype">
<property name="allowedFields" value="${allowedFields}" />
<aop:scoped-proxy />
</bean>
<bean id="webBindingInitializer" class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="messageCodesResolver" ref="codesResolver" />
</bean>
Because binder instance is passed into it in handlerAdapter. How can I set up the binder then ?
There is no way of setting it up in xml configuration. You must implement your custom WebBindingInitializer ... The ConfigurableWebBindingInitializer is obviously missing the possibility of setting up allowed and restricted fields...
Or you can vote up SPR-8601
This is very old, however for anyone that dislike the use of annotations in production code (like me) here is a solution I found to add a init binder without use of annotations. You only need to overwrite initBinder method that extends from most of base controllers provided by Spring:
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception
{
System.out.println("Binding!!!!!");
super.initBinder(request, binder);
binder.registerCustomEditor(Double.class, new CurrencyPropertyEditor());
}
Where my CurrencyPropertyEditor class is a subclass of java.beans.PropertyEditorSupport with getAsText, getValue, setValue and setAsText methods overwrited as well.
Hope it helps!!!

Resources