问题
A very quick question ,to which there seems to be no easy answer.
Is it possible to put an object directly under the embedded resources using Spring HATEOAS? The desired output format in JSON should look like
{
...
_embedded: {
myObject: {
...
}
}
}
Using the code below, I always end up with a colletion for any resource I want to embed.
ArrayList<Resource<?>> embeddedContent = new ArrayList<>();
Resource<MyObject> myObjectResource = new Resource<MyObject>(new MyObject());
embeddedContent.add(myObjectResource );
Resources<Resource<?>> embeddedResources = new Resources<Resource<?>>(embeddedContent);
The embeddedResources
are then put on a class, which is later mapped to a resource as well.
But for some reason, even though I'm not adding a collection to the embedded resources, the output still shows the myObject
embedded resource as an array:
{
...
_embedded: {
myObject: [
{
...
}
]
}
}
回答1:
The parameter enforceEmbeddedCollections in this constructor allow represent embedded arrays like a object.
public HalHandlerInstantiator(RelProvider resolver, CurieProvider curieProvider, boolean enforceEmbeddedCollections) {}
So, you should set HalHandlerInstantiator with value false. There is a small example:
ObjectMapper halObjectMapper = new ObjectMapper();
halObjectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
halObjectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
halObjectMapper
.setHandlerInstantiator(new Jackson2HalModule.
HalHandlerInstantiator(new DefaultRelProvider(), null, false));
Jackson2HalModule jackson2HalModule = new Jackson2HalModule();
halObjectMapper.registerModule(jackson2HalModule);
try {
halObjectMapper.writeValueAsString(new Resources<Album>(Arrays.asList(new Album("1", "title", "1", 1))));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
回答2:
Add the following snippet to one of your @Configuration
classes. The code here looks similar to what can be found in org.springframework.hateoas.config.HypermediaSupportBeanDefinitionRegistrar
. We're basically overwriting the HalHandlerInstantiator
in the HAL-ObjectMapper where we pass false
to the enforceEmbeddedCollections
argument. This is a dirty hack, but currently there's no way to configure this aspect of the spring-hateoas machinery.
@Bean
BeanPostProcessor halModuleReconfigurer(BeanFactory beanFactory) {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
if (bean instanceof RequestMappingHandlerAdapter) {
RequestMappingHandlerAdapter adapter = (RequestMappingHandlerAdapter) bean;
adapter.setMessageConverters(reconfigureObjectMapper(adapter.getMessageConverters()));
}
if (bean instanceof AnnotationMethodHandlerAdapter) {
AnnotationMethodHandlerAdapter adapter = (AnnotationMethodHandlerAdapter) bean;
List<HttpMessageConverter<?>> augmentedConverters = reconfigureObjectMapper(Arrays.asList(adapter
.getMessageConverters()));
adapter
.setMessageConverters(augmentedConverters.toArray(new HttpMessageConverter<?>[augmentedConverters.size()]));
}
if (bean instanceof RestTemplate) {
RestTemplate template = (RestTemplate) bean;
template.setMessageConverters(reconfigureObjectMapper(template.getMessageConverters()));
}
return bean;
}
private List<HttpMessageConverter<?>> reconfigureObjectMapper(final List<HttpMessageConverter<?>> converters) {
for (HttpMessageConverter<?> converter : converters) {
if (converter instanceof MappingJackson2HttpMessageConverter) {
MappingJackson2HttpMessageConverter halConverterCandidate = (MappingJackson2HttpMessageConverter) converter;
ObjectMapper objectMapper = halConverterCandidate.getObjectMapper();
if (Jackson2HalModule.isAlreadyRegisteredIn(objectMapper)) {
final CurieProvider curieProvider = Try.of(() -> beanFactory.getBean(CurieProvider.class)).getOrElse((CurieProvider) null);
final RelProvider relProvider = beanFactory.getBean("_relProvider", RelProvider.class);
final MessageSourceAccessor linkRelationMessageSource = beanFactory.getBean("linkRelationMessageSource", MessageSourceAccessor.class);
objectMapper.setHandlerInstantiator(new Jackson2HalModule.HalHandlerInstantiator(relProvider, curieProvider, linkRelationMessageSource, false));
}
}
}
return converters;
}
};
}
来源:https://stackoverflow.com/questions/33777198/embed-object-instead-of-collection-in-spring-hateoas