From c23c7b9cc74fd921d96748460c6a14c25482e290 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 26 Jul 2016 18:28:48 +0200 Subject: [PATCH] =?UTF-8?q?DATACMNS-885=20-=20Fixed=20implementation=20of?= =?UTF-8?q?=20canRead(=E2=80=A6)=20for=20projecting=20HttpMessageConverter?= =?UTF-8?q?s.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changed the implementation of both the JSON Path and XPath based projecting HttpMessageConverters to make sure the cached decisions don't depend on the media type. Reuse the evaluation of the media type in AbstractHttpMessageConverter. --- ...rojectingJackson2HttpMessageConverter.java | 18 +++++++-- .../data/web/XmlBeamHttpMessageConverter.java | 35 +++++++---------- .../XmlBeamHttpMessageConverterUnitTests.java | 39 +++++++++++++++++++ 3 files changed, 66 insertions(+), 26 deletions(-) diff --git a/src/main/java/org/springframework/data/web/ProjectingJackson2HttpMessageConverter.java b/src/main/java/org/springframework/data/web/ProjectingJackson2HttpMessageConverter.java index 4d2f16da7..bda6f47e0 100644 --- a/src/main/java/org/springframework/data/web/ProjectingJackson2HttpMessageConverter.java +++ b/src/main/java/org/springframework/data/web/ProjectingJackson2HttpMessageConverter.java @@ -113,22 +113,32 @@ public class ProjectingJackson2HttpMessageConverter extends MappingJackson2HttpM @Override public boolean canRead(Type type, Class contextClass, MediaType mediaType) { - Class rawType = ResolvableType.forType(type).getRawClass(); + if (!canRead(mediaType)) { + return false; + } + Class rawType = ResolvableType.forType(type).getRawClass(); Boolean result = supportedTypesCache.get(rawType); if (result != null) { return result; } - result = canRead(mediaType) && rawType.isInterface() - && AnnotationUtils.findAnnotation(rawType, ProjectedPayload.class) != null; - + result = rawType.isInterface() && AnnotationUtils.findAnnotation(rawType, ProjectedPayload.class) != null; supportedTypesCache.put(rawType, result); return result; } + /* + * (non-Javadoc) + * @see org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter#canWrite(java.lang.Class, org.springframework.http.MediaType) + */ + @Override + public boolean canWrite(Class clazz, MediaType mediaType) { + return false; + } + /* * (non-Javadoc) * @see org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter#read(java.lang.reflect.Type, java.lang.Class, org.springframework.http.HttpInputMessage) diff --git a/src/main/java/org/springframework/data/web/XmlBeamHttpMessageConverter.java b/src/main/java/org/springframework/data/web/XmlBeamHttpMessageConverter.java index 8fc17bcc7..9704232b8 100644 --- a/src/main/java/org/springframework/data/web/XmlBeamHttpMessageConverter.java +++ b/src/main/java/org/springframework/data/web/XmlBeamHttpMessageConverter.java @@ -16,8 +16,6 @@ package org.springframework.data.web; import java.io.IOException; -import java.util.Collections; -import java.util.List; import java.util.Map; import org.springframework.core.ResolvableType; @@ -25,6 +23,7 @@ import org.springframework.core.annotation.AnnotationUtils; import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpOutputMessage; import org.springframework.http.MediaType; +import org.springframework.http.converter.AbstractHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotWritableException; @@ -39,7 +38,7 @@ import org.xmlbeam.XBProjector; * @see http://www.xmlbeam.org * @soundtrack Dr. Kobayashi Maru & The Mothership Connection - Anthem (EPisode One) */ -public class XmlBeamHttpMessageConverter implements HttpMessageConverter { +public class XmlBeamHttpMessageConverter extends AbstractHttpMessageConverter { private final ProjectionFactory projectionFactory; private final Map, Boolean> supportedTypesCache = new ConcurrentReferenceHashMap, Boolean>(); @@ -48,26 +47,27 @@ public class XmlBeamHttpMessageConverter implements HttpMessageConverter * Creates a new {@link XmlBeamHttpMessageConverter}. */ public XmlBeamHttpMessageConverter() { + + super(MediaType.APPLICATION_XML, MediaType.parseMediaType("application/*+xml")); + this.projectionFactory = new XBProjector(); } - /* + /* * (non-Javadoc) - * @see org.springframework.http.converter.HttpMessageConverter#canRead(java.lang.Class, org.springframework.http.MediaType) + * @see org.springframework.http.converter.AbstractHttpMessageConverter#supports(java.lang.Class) */ @Override - public boolean canRead(Class type, MediaType mediaType) { + protected boolean supports(Class type) { Class rawType = ResolvableType.forType(type).getRawClass(); - Boolean result = supportedTypesCache.get(rawType); if (result != null) { return result; } - result = mediaType.isCompatibleWith(MediaType.APPLICATION_XML) && rawType.isInterface() - && AnnotationUtils.findAnnotation(rawType, ProjectedPayload.class) != null; + result = rawType.isInterface() && AnnotationUtils.findAnnotation(rawType, ProjectedPayload.class) != null; supportedTypesCache.put(rawType, result); @@ -85,28 +85,19 @@ public class XmlBeamHttpMessageConverter implements HttpMessageConverter /* * (non-Javadoc) - * @see org.springframework.http.converter.HttpMessageConverter#getSupportedMediaTypes() + * @see org.springframework.http.converter.AbstractHttpMessageConverter#readInternal(java.lang.Class, org.springframework.http.HttpInputMessage) */ @Override - public List getSupportedMediaTypes() { - return Collections.singletonList(MediaType.APPLICATION_XML); - } - - /* - * (non-Javadoc) - * @see org.springframework.http.converter.HttpMessageConverter#read(java.lang.Class, org.springframework.http.HttpInputMessage) - */ - @Override - public Object read(Class clazz, HttpInputMessage inputMessage) + protected Object readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { return projectionFactory.io().stream(inputMessage.getBody()).read(clazz); } /* * (non-Javadoc) - * @see org.springframework.http.converter.HttpMessageConverter#write(java.lang.Object, org.springframework.http.MediaType, org.springframework.http.HttpOutputMessage) + * @see org.springframework.http.converter.AbstractHttpMessageConverter#writeInternal(java.lang.Object, org.springframework.http.HttpOutputMessage) */ @Override - public void write(Object t, MediaType contentType, HttpOutputMessage outputMessage) + protected void writeInternal(Object t, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {} } diff --git a/src/test/java/org/springframework/data/web/XmlBeamHttpMessageConverterUnitTests.java b/src/test/java/org/springframework/data/web/XmlBeamHttpMessageConverterUnitTests.java index 957bfee56..37d81214e 100644 --- a/src/test/java/org/springframework/data/web/XmlBeamHttpMessageConverterUnitTests.java +++ b/src/test/java/org/springframework/data/web/XmlBeamHttpMessageConverterUnitTests.java @@ -26,7 +26,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.data.web.ProjectingJackson2HttpMessageConverterUnitTests.UnannotatedInterface; import org.springframework.http.HttpInputMessage; +import org.springframework.http.MediaType; import org.xmlbeam.annotation.XBRead; /** @@ -70,10 +72,45 @@ public class XmlBeamHttpMessageConverterUnitTests { assertThat(customer.getLastname(), is("Matthews")); } + /** + * @see DATACMNS-885 + */ + @Test + public void supportsAnnotatedInterface() { + assertThat(converter.canRead(Customer.class, MediaType.APPLICATION_XML), is(true)); + } + + /** + * @see DATACMNS-885 + */ + @Test + public void supportsXmlBasedMediaType() { + assertThat(converter.canRead(Customer.class, MediaType.APPLICATION_ATOM_XML), is(true)); + } + + /** + * @see DATACMNS-885 + */ + @Test + public void doesNotSupportUnannotatedInterface() { + assertThat(converter.canRead(UnannotatedInterface.class, MediaType.APPLICATION_XML), is(false)); + } + + /** + * @see DATACMNS-885 + */ + @Test + public void supportsInterfaceAfterLookupForDifferrentMediaType() { + + assertThat(converter.canRead(Customer.class, MediaType.APPLICATION_JSON), is(false)); + assertThat(converter.canRead(Customer.class, MediaType.APPLICATION_XML), is(true)); + } + private void preparePayload(String payload) throws IOException { when(message.getBody()).thenReturn(new ByteArrayInputStream(payload.getBytes())); } + @ProjectedPayload public interface Customer { @XBRead("//firstname") @@ -82,4 +119,6 @@ public class XmlBeamHttpMessageConverterUnitTests { @XBRead("//lastname") String getLastname(); } + + public interface UnnannotatedInterface {} }