-
Notifications
You must be signed in to change notification settings - Fork 472
HttpMessageConverters not prepended with HAL Message Converter #134
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I am experiencing this issue on Spring 4.0.1 as well. Spring Hateoas 0.9.0 RELEASE |
Ok great thx! |
Any workaround for Spring Hateoas 0.9.0.RELEASE? |
In short yes. What we did is the following (let me know if you need specific code details) We have already were extending the MappingJackson2HttpMessageConverter in a class called MappingJsonJackson2HttpMessageConverter. In a @PostContruct method of that class we call the method MappingJackson2HttpMessageConverter#setObjectMapper. We pass it a custom HalJacksonObjectMapper which looks like :
Hope that helps. |
Thank you @SirMaster . So do I just use the MappingJsonJackson2HttpMessageConverter inside Jackson2ModuleRegisteringBeanPostProcessor#potentiallyRegisterModule? What else do I need to change?
Could you post the complete MappingJsonJackson2HttpMessageConverter code? Thanks. |
I just directly updated Jackson2ModuleRegisteringBeanPostProcessor#potentiallyRegisterModule, and it can return HAL now. Not sure if it is the right fix:
|
@jiwhiz, I think that could work yes. We did it a little different, but from what I am seeing of your code I think in essence it's the same, see : MappingJsonJackson2HttpMessageConverter.java
And in our config class we tell it to add it to the HttpMessageConverters, see ApplicationConfig.java
|
I missed the configuration change, no wonder couldn't get your workaround work. Since I don't need a customized MappingJackson2HttpMessageConverter, my hack will be fine to me. Thanks a lot! |
Sorry about that, I should have just posted the whole thing and save you some time. |
No problem at all. I was so frustrated when I couldn't get HAL message returned, until saw your issue report. You pointed out where the problem is, and that saved me lots of time. |
Another issue I found is to add HAL_JSON to supportedMediaTypes, not to set it as the supportedMediaTypes. Otherwise I got "415 (Unsupported Media Type)". The updated code is
|
Is anyone able to come up with a test case that shows, this issue really exists? I don't necessarily doubt it, but I've seen the current code working flawlessly in standard Spring MVC applications. We also use it heavily in the Spring Data REST test code. So I am interested in finding out what is actually causing the erroneous behavior. I can't see anything obviously wrong here, as we're simply re-setting the |
Hi Oliver, I created a very simple application to demonstrate the issue, see my CIExample project in GitHub https://github.com/jiwhiz/CIExample. This example was built and deployed by CloudBee and you can access it at http://ciexample.jiwhiz.cloudbees.net/ The backend will expose a simple RESTful API "http://ciexample.jiwhiz.cloudbees.net/api/user", if you use any rest client, like Advanced Rest Client from Chrome shop, you can see the return json object is like:
Definitely it is not HAL. If I change the code as my previous comments, it works, the output json is:
Please see the config file and let me know what the problem is:
Thanks a lot! Yuan |
Hi @olivergierke, i use spring-hateoas without Spring Data REST and run into the same problem. spring-hateoas with @EnableHypermediaSupport re-setting the messageConverters property after the RequestMappingHandlerAdapter.afterPropertiesSet() was called. After @EnableHypermediaSupport configuration applied, the RequestMappingHandlerAdapter instance holds the modified messageConverters but the earlier created instances of HttpEntityMethodProcessor (created after RMHA.afterPropertiesSet() was called) still contains the old list of messageConverters without the new HAL Jackson Converter. |
That's very helpful observation, @stefanbickel! Seems like we need to re-invoke |
The Jackson(2)ModuleRegisteringBeanPostProcessor now uses postProcess*Before*Initialization to make sure, afterPropertiesSet() has not been called on the target components which might have propagated the original HttpMessageConverters into other internal components. With this fix, adding the HttpMessageConverter for HAL is added before the call and thus will be propagated to downstream components.
Would you guys mind giving the current snapshots a spin? We're simply using the correct callback method ( |
@olivergierke, yes, this issue was fixed, and I can get HAL messages now. Excellent! |
@olivergierke nice work! It seems that while the HAL module is doing its job, global message conversion settings are lost. In my project we extend WebMvcConfigurerAdapter and override configureMessageConverters to allow mapping of some complex types, use special date formatting and to exclude nulls. Is this to be expected or should the mappers be blended? FYI, if I turn off HAL support, all my custom mapper settings work as expected with the standard hateoas link support. |
What exactly does "are lost" mean? What we effectively do is registering an additional If you happen to work with Spring Boot, all (global) beans of type Does that help? |
@olivergierke Leaving out all other configurations, this is what we are doing: @Configuration
@EnableWebMvc
@EnableHypermediaSupport(type = HypermediaType.HAL)
@EnableSpringDataWebSupport
@ComponentScan(basePackages = { ... })
@PropertySource({ ... })
public class MvcConfig extends WebMvcConfigurerAdapter {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(MvcObjectMapper.getInstance().getObjectMapper());
converters.add(converter);
}
} So, we also want to register an additional HttpMessageConverter with an independent ObjectMapper. Shouldn't they both be applied during serialization? |
So i tried your solution and customized ... added to previous comment ...
/**
* @see org.springframework.hateoas.config.HypermediaSupportBeanDefinitionRegistrar
*/
private static final String HAL_OBJECT_MAPPER_BEAN_NAME = "_halObjectMapper";
@Resource(name = HAL_OBJECT_MAPPER_BEAN_NAME)
public void customizeHalObjectMapper(ObjectMapper mapper) {
mapper.registerModule(new MyCustomModule1());
mapper.registerModule(new MyCustomModule2());
mapper.registerModule(new MyCustomModule3());
mapper.setDateFormat(MY_CUSTOM_DATE_FORMAT);
mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
mapper.setSerializationInclusion(Include.NON_EMPTY);
} It does work for Response serialization as expected. I still have to override Is it the expectation that both Requests and Responses should have a content type of Am I missing something? What would you suggest? |
this is fixed in 0.10, correct? |
Not sure if it's the same issue, but my HAL output is also broken in 0.16.0 and I narrowed it down to the I've added a commit to the The single resource output is fine:
But the collection output is wrong:
Adding
|
That's expected behavior. According to the HAL specification the root document needs to be a Resource Object, which it isn't in case you're returning a The behavior is pretty straight-forward. You need to return something extending |
Thanks, that's very helpful information, changing the media type to Regarding the collection resources I'm a bit confused though - in all the samples and in |
The easiest way is to return an instances of |
Simplest way to reproduce the behaviour would be to check out my fork of the
Access Thanks again, maybe it'd be good to mention the recommended usage of |
See #833 for how to create a custom media type. See #416 and #833 such that |
Hi,
On the startup of our application Spring instantiates certain processors like HttpEntityMethodProcessor and RequestResponseBodyMethodProcessor. These will be created with a reference to a list of HttpMessageConverters.
The list instance is set in the abstract class AbstractMessageConverterMethodArgumentResolver#messageConverters. But because some of the processors get created before HypermediaSupportBeanDefinitionRegistrar#registerBeanDefinitions is called it occurs that the replacing of the HttpMessageConverters will not have the proper effect.
I.e. HypermediaSupportBeanDefinitionRegistrar#registerBeanDefinitions does :
Jackson2ModuleRegisteringBeanPostProcessor#postProcessAfterInitialization does
Jackson2ModuleRegisteringBeanPostProcessor#potentiallyRegisterModule does
The problem seems to be here in potentiallyRegisterModule, it returns a new List of HttpMessageConverts while there are still objects looking at the original list.
I tested this with :
Spring 3.2.5
Spring Hateoas 0.9.0.BUILD-SNAPSHOT
Many thx in advance for any input on this.
M.
The text was updated successfully, but these errors were encountered: