From 7cabdc3cd6e5f9e480fed7d79d5375f8d07e347a Mon Sep 17 00:00:00 2001 From: Greg Whitaker Date: Thu, 22 Sep 2016 11:17:55 -0700 Subject: [PATCH] Feature/springboot (#3) Added a new catnap-springboot module to address Issue #2 --- README.md | 3 +- build.gradle | 9 ++ .../catnap-examples-springboot/build.gradle | 2 +- .../springboot/WidgetApplication.java | 2 +- .../controller/WidgetController.java | 2 +- catnap-springboot/README.md | 2 + catnap-springboot/build.gradle | 27 +++++ .../annotation/CatnapResponseBody.java | 39 +++++++ .../springboot/annotation/EnableCatnap.java | 34 ++++++ .../config/CatnapWebMvcConfigurerAdapter.java | 43 ++++++++ .../CatnapDisabledHandlerInterceptor.java | 39 +++++++ .../CatnapResponseBodyHandlerInterceptor.java | 76 +++++++++++++ .../CatnapJsonMessageConverter.java | 43 ++++++++ .../CatnapJsonpMessageConverter.java | 43 ++++++++ .../CatnapMessageConverter.java | 87 +++++++++++++++ .../springboot/view/CatnapWrappingView.java | 101 ++++++++++++++++++ .../catnap/springboot/view/WrappingView.java | 41 +++++++ gradle.properties | 2 +- settings.gradle | 2 +- 19 files changed, 591 insertions(+), 6 deletions(-) create mode 100644 catnap-springboot/README.md create mode 100644 catnap-springboot/build.gradle create mode 100644 catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/annotation/CatnapResponseBody.java create mode 100644 catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/annotation/EnableCatnap.java create mode 100644 catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/config/CatnapWebMvcConfigurerAdapter.java create mode 100644 catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/interceptor/CatnapDisabledHandlerInterceptor.java create mode 100644 catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/interceptor/CatnapResponseBodyHandlerInterceptor.java create mode 100644 catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/messageconverters/CatnapJsonMessageConverter.java create mode 100644 catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/messageconverters/CatnapJsonpMessageConverter.java create mode 100644 catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/messageconverters/CatnapMessageConverter.java create mode 100644 catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/view/CatnapWrappingView.java create mode 100644 catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/view/WrappingView.java diff --git a/README.md b/README.md index 1fcef24..ee8e1fc 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,8 @@ As you can see the partial response is a significant reduction in payload size a ##Getting Catnap Catnap libraries are available from JCenter. -* [catnap-spring](https://bintray.com/gregwhitaker/maven/catnap-spring) - Use this library if you are integrating Catnap with a SpringMVC or Spring Boot application. +* [catnap-spring](https://bintray.com/gregwhitaker/maven/catnap-spring) - Use this library if you are integrating Catnap with a SpringMVC. +* [catnap-springboot](https://bintray.com/gregwhitaker/maven/catnap-springboot) - Use this library if you are integrating Catnap with Spring Boot. * [catnap-jaxrs](https://bintray.com/gregwhitaker/maven/catnap-jaxrs) - Use this library if you are integrating Catnap with a Jersey or RESTEasy application. ##Getting Started with Catnap diff --git a/build.gradle b/build.gradle index 782d838..bd9b0f7 100644 --- a/build.gradle +++ b/build.gradle @@ -34,3 +34,12 @@ project(":catnap-spring") { maven { url "https://repo.spring.io/milestone" } } } + +project(":catnap-springboot") { + ext.artifact = 'catnap-springboot' + + repositories { + maven { url "https://repo.spring.io/snapshot" } + maven { url "https://repo.spring.io/milestone" } + } +} diff --git a/catnap-examples/catnap-examples-springboot/build.gradle b/catnap-examples/catnap-examples-springboot/build.gradle index d7bd484..8db39c5 100644 --- a/catnap-examples/catnap-examples-springboot/build.gradle +++ b/catnap-examples/catnap-examples-springboot/build.gradle @@ -20,7 +20,7 @@ repositories { } dependencies { - compile 'com.github.gregwhitaker:catnap-spring:2.0.0' + compile project(":catnap-springboot") compile('org.springframework.boot:spring-boot-starter-web') } \ No newline at end of file diff --git a/catnap-examples/catnap-examples-springboot/src/main/java/catnap/examples/springboot/WidgetApplication.java b/catnap-examples/catnap-examples-springboot/src/main/java/catnap/examples/springboot/WidgetApplication.java index 787cfbd..2803032 100644 --- a/catnap-examples/catnap-examples-springboot/src/main/java/catnap/examples/springboot/WidgetApplication.java +++ b/catnap-examples/catnap-examples-springboot/src/main/java/catnap/examples/springboot/WidgetApplication.java @@ -16,7 +16,7 @@ package catnap.examples.springboot; -import com.github.gregwhitaker.catnap.springmvc.annotation.EnableCatnap; +import com.github.gregwhitaker.catnap.springboot.annotation.EnableCatnap; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/catnap-examples/catnap-examples-springboot/src/main/java/catnap/examples/springboot/controller/WidgetController.java b/catnap-examples/catnap-examples-springboot/src/main/java/catnap/examples/springboot/controller/WidgetController.java index 7b261e7..b1895b1 100644 --- a/catnap-examples/catnap-examples-springboot/src/main/java/catnap/examples/springboot/controller/WidgetController.java +++ b/catnap-examples/catnap-examples-springboot/src/main/java/catnap/examples/springboot/controller/WidgetController.java @@ -20,7 +20,7 @@ import catnap.examples.springboot.model.Widget; import catnap.examples.springboot.service.WidgetService; import com.github.gregwhitaker.catnap.core.annotation.CatnapDisabled; -import com.github.gregwhitaker.catnap.springmvc.annotation.CatnapResponseBody; +import com.github.gregwhitaker.catnap.springboot.annotation.CatnapResponseBody; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; diff --git a/catnap-springboot/README.md b/catnap-springboot/README.md new file mode 100644 index 0000000..ea58c4e --- /dev/null +++ b/catnap-springboot/README.md @@ -0,0 +1,2 @@ +catnap-springboot +=== diff --git a/catnap-springboot/build.gradle b/catnap-springboot/build.gradle new file mode 100644 index 0000000..66b4743 --- /dev/null +++ b/catnap-springboot/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'java' + +apply from: file('../gradle/codequality.gradle') +apply from: file('../gradle/release.gradle') +apply from: file('../gradle/convention.gradle') + +apply plugin: 'io.spring.dependency-management' + +dependencyManagement { + imports { + mavenBom "io.spring.platform:platform-bom:2.0.4.RELEASE" + } +} + +dependencies { + compile project(':catnap-core') + + compile('org.springframework:spring-webmvc') + compile('commons-io:commons-io:2.5') + compile('org.slf4j:slf4j-api:1.7.21') + compile('commons-logging:commons-logging:1.2') + + testCompile('org.springframework:spring-test') + testCompile('junit:junit:4.12') + testCompile('org.hamcrest:hamcrest-all:1.3') + testCompile('org.mockito:mockito-all:1.10.19') +} diff --git a/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/annotation/CatnapResponseBody.java b/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/annotation/CatnapResponseBody.java new file mode 100644 index 0000000..d376838 --- /dev/null +++ b/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/annotation/CatnapResponseBody.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 Greg Whitaker + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.gregwhitaker.catnap.springboot.annotation; + +import com.github.gregwhitaker.catnap.core.annotation.CatnapAnnotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +@CatnapAnnotation +public @interface CatnapResponseBody { + + /** + * Optional argument that defines the name of the desired + * object in the returned model you wish to have rendered + * by Catnap. If a value is not supplied the class name + * of the return type of the annotated method will be + * used. + */ + public String value() default ""; +} diff --git a/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/annotation/EnableCatnap.java b/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/annotation/EnableCatnap.java new file mode 100644 index 0000000..93391ef --- /dev/null +++ b/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/annotation/EnableCatnap.java @@ -0,0 +1,34 @@ +/* + * Copyright 2016 Greg Whitaker + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.gregwhitaker.catnap.springboot.annotation; + +import com.github.gregwhitaker.catnap.core.annotation.CatnapAnnotation; +import com.github.gregwhitaker.catnap.springboot.config.CatnapWebMvcConfigurerAdapter; +import org.springframework.context.annotation.Import; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +@CatnapAnnotation +@Import({CatnapWebMvcConfigurerAdapter.class}) +public @interface EnableCatnap { + +} diff --git a/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/config/CatnapWebMvcConfigurerAdapter.java b/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/config/CatnapWebMvcConfigurerAdapter.java new file mode 100644 index 0000000..6e0753b --- /dev/null +++ b/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/config/CatnapWebMvcConfigurerAdapter.java @@ -0,0 +1,43 @@ +/* + * Copyright 2016 Greg Whitaker + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.gregwhitaker.catnap.springboot.config; + +import com.github.gregwhitaker.catnap.springboot.messageconverters.CatnapJsonMessageConverter; +import com.github.gregwhitaker.catnap.springboot.messageconverters.CatnapJsonpMessageConverter; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +import java.util.List; + +@Configuration +public class CatnapWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter { + + @Override + public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { + configurer.mediaType("json", MediaType.APPLICATION_JSON); + configurer.mediaType("jsonp", new MediaType("application", "x-javascript")); + } + + @Override + public void configureMessageConverters(List> converters) { + converters.add(new CatnapJsonMessageConverter()); + converters.add(new CatnapJsonpMessageConverter()); + } +} diff --git a/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/interceptor/CatnapDisabledHandlerInterceptor.java b/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/interceptor/CatnapDisabledHandlerInterceptor.java new file mode 100644 index 0000000..6f5e76f --- /dev/null +++ b/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/interceptor/CatnapDisabledHandlerInterceptor.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 Greg Whitaker + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.gregwhitaker.catnap.springboot.interceptor; + +import com.github.gregwhitaker.catnap.core.annotation.CatnapDisabled; +import com.github.gregwhitaker.catnap.core.util.RequestUtil; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class CatnapDisabledHandlerInterceptor extends HandlerInterceptorAdapter { + + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) + throws Exception { + HandlerMethod method = (HandlerMethod) handler; + + if (method.getMethodAnnotation(CatnapDisabled.class) != null) { + RequestUtil.disableCatnap(request); + } + } +} diff --git a/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/interceptor/CatnapResponseBodyHandlerInterceptor.java b/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/interceptor/CatnapResponseBodyHandlerInterceptor.java new file mode 100644 index 0000000..987ea04 --- /dev/null +++ b/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/interceptor/CatnapResponseBodyHandlerInterceptor.java @@ -0,0 +1,76 @@ +/* + * Copyright 2016 Greg Whitaker + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.gregwhitaker.catnap.springboot.interceptor; + +import com.github.gregwhitaker.catnap.core.exception.ViewRenderException; +import com.github.gregwhitaker.catnap.springboot.annotation.CatnapResponseBody; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.beans.Introspector; +import java.util.List; +import java.util.Map; + +public class CatnapResponseBodyHandlerInterceptor extends HandlerInterceptorAdapter { + public static final String MODEL_NAME = "catnapModel"; + + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) + throws Exception { + HandlerMethod method = (HandlerMethod) handler; + + if (method.getMethodAnnotation(ResponseBody.class) == null) { + CatnapResponseBody annotation = method.getMethodAnnotation(CatnapResponseBody.class); + + if (annotation != null) { + String modelName = modelName(annotation, method); + + if (modelAndView != null) { + //Transfer the model to a well known key so that we can retrieve it in the view. + Object model = modelAndView.getModel().get(modelName); + modelAndView.getModel().put(MODEL_NAME, model); + } + } + } + } + + private String modelName(CatnapResponseBody annotation, HandlerMethod method) { + if (!StringUtils.isEmpty(annotation.value())) { + return annotation.value(); + } else { + if (List.class.isAssignableFrom(method.getReturnType().getParameterType())) { + String paramType = method.getReturnType().getGenericParameterType().getTypeName(); + paramType = paramType.substring(paramType.lastIndexOf(".") + 1, paramType.length() - 1); + return Introspector.decapitalize(paramType) + "List"; + } + + if (Map.class.isAssignableFrom(method.getReturnType().getParameterType())) { + throw new ViewRenderException("Map is not a supported return type for methods annotated with " + + "@CatnapResponseBody. Please return an object or a list of objects. If you wish to return " + + "a map then you must use Catnap's standard model and view handling by removing the " + + "@CatnapResponseBody annotation."); + } + + return Introspector.decapitalize(method.getReturnType().getParameterType().getSimpleName()); + } + } +} diff --git a/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/messageconverters/CatnapJsonMessageConverter.java b/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/messageconverters/CatnapJsonMessageConverter.java new file mode 100644 index 0000000..3c606b0 --- /dev/null +++ b/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/messageconverters/CatnapJsonMessageConverter.java @@ -0,0 +1,43 @@ +/* + * Copyright 2016 Greg Whitaker + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.gregwhitaker.catnap.springboot.messageconverters; + +import com.github.gregwhitaker.catnap.core.view.JsonCatnapView; + +/** + * An {@link org.springframework.http.converter.AbstractHttpMessageConverter} implementation that renders JSON + * responses with Catnap. + */ +public class CatnapJsonMessageConverter extends CatnapMessageConverter { + + /** + * Initializes this instance of {@link CatnapJsonMessageConverter} with the default {@link JsonCatnapView} + * configured for rendering responses. + */ + public CatnapJsonMessageConverter() { + super(new JsonCatnapView.Builder().build()); + } + + /** + * Initializes this instance of {@link CatnapJsonMessageConverter}. + * + * @param view the {@link JsonCatnapView} to use when rendering responses within this message converter + */ + public CatnapJsonMessageConverter(JsonCatnapView view) { + super(view); + } +} diff --git a/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/messageconverters/CatnapJsonpMessageConverter.java b/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/messageconverters/CatnapJsonpMessageConverter.java new file mode 100644 index 0000000..e546e26 --- /dev/null +++ b/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/messageconverters/CatnapJsonpMessageConverter.java @@ -0,0 +1,43 @@ +/* + * Copyright 2016 Greg Whitaker + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.gregwhitaker.catnap.springboot.messageconverters; + +import com.github.gregwhitaker.catnap.core.view.JsonpCatnapView; + +/** + * An {@link org.springframework.http.converter.AbstractHttpMessageConverter} implementation that renders JSONP + * responses with Catnap. + */ +public class CatnapJsonpMessageConverter extends CatnapMessageConverter { + + /** + * Initializes this instance of {@link CatnapJsonpMessageConverter} with the default {@link JsonpCatnapView} + * configured for rendering responses. + */ + public CatnapJsonpMessageConverter() { + super(new JsonpCatnapView.Builder().build()); + } + + /** + * Initializes this instance of {@link CatnapJsonpMessageConverter}. + * + * @param view the {@link JsonpCatnapView} to use when rendering responses within this message converter + */ + public CatnapJsonpMessageConverter(JsonpCatnapView view) { + super(view); + } +} diff --git a/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/messageconverters/CatnapMessageConverter.java b/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/messageconverters/CatnapMessageConverter.java new file mode 100644 index 0000000..3841ccf --- /dev/null +++ b/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/messageconverters/CatnapMessageConverter.java @@ -0,0 +1,87 @@ +/* + * Copyright 2016 Greg Whitaker + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.gregwhitaker.catnap.springboot.messageconverters; + +import com.github.gregwhitaker.catnap.core.exception.ViewRenderException; +import com.github.gregwhitaker.catnap.core.view.CatnapView; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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.HttpMessageNotReadableException; +import org.springframework.http.converter.HttpMessageNotWritableException; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @param + */ +public abstract class CatnapMessageConverter extends AbstractHttpMessageConverter { + private static final Logger LOG = LoggerFactory.getLogger(CatnapMessageConverter.class); + + private final T view; + + public CatnapMessageConverter(final T view) { + super(MediaType.valueOf(view.getContentType())); + this.view = view; + } + + @Override + protected boolean supports(Class clazz) { + HttpServletRequest httpRequest = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); + + if (httpRequest.getParameter("fields") != null) { + return Object.class.isAssignableFrom(clazz); + } + + return false; + } + + @Override + protected boolean canRead(MediaType mediaType) { + // Catnap message converters are write-only + return false; + } + + @Override + protected Object readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { + // Catnap message converters are write-only + return null; + } + + @Override + protected void writeInternal(Object obj, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { + HttpServletRequest httpRequest = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); + HttpServletResponse httpResponse = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getResponse(); + + httpResponse.setContentType(view.getContentType()); + httpResponse.setCharacterEncoding(view.getEncoding()); + + try { + view.render(httpRequest, httpResponse, obj); + } catch (Exception e) { + LOG.error("Exception encountered during view rendering!", e); + throw new ViewRenderException("Exception encountered during view rendering!", e); + } + } +} diff --git a/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/view/CatnapWrappingView.java b/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/view/CatnapWrappingView.java new file mode 100644 index 0000000..87172f8 --- /dev/null +++ b/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/view/CatnapWrappingView.java @@ -0,0 +1,101 @@ +/* + * Copyright 2016 Greg Whitaker + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.gregwhitaker.catnap.springboot.view; + +import com.github.gregwhitaker.catnap.core.view.CatnapView; +import com.github.gregwhitaker.catnap.springboot.interceptor.CatnapResponseBodyHandlerInterceptor; +import org.springframework.http.HttpStatus; +import org.springframework.web.servlet.View; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Map; + +public class CatnapWrappingView implements View, WrappingView { + public static final String DEFAULT_MODELNAME = "result"; + + private final CatnapView catnapView; + private final String modelName; + + public CatnapWrappingView(final CatnapView view) { + this(view, DEFAULT_MODELNAME); + } + + public CatnapWrappingView(final CatnapView view, final String modelName) { + this.catnapView = view; + this.modelName = modelName; + } + + @Override + public void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { + setContentTypeHeader(response); + + catnapView.render(request, response, extractResult(model), httpStatus(request)); + } + + public void setContentTypeHeader(HttpServletResponse response) { + response.setContentType(getContentType()); + response.setCharacterEncoding(getCharacterEncoding()); + } + + public com.github.gregwhitaker.catnap.core.context.HttpStatus httpStatus(HttpServletRequest request) { + Object attr = request.getAttribute(RESPONSE_STATUS_ATTRIBUTE); + + if (attr != null) { + int value = ((HttpStatus) attr).value(); + return com.github.gregwhitaker.catnap.core.context.HttpStatus.valueOf(value); + } + + return com.github.gregwhitaker.catnap.core.context.HttpStatus.OK; + } + + public Object extractResult(Map model) { + if (model != null && !model.isEmpty()) { + if (model.size() == 1) { + return model.values().iterator().next(); + } else { + if (model.containsKey(CatnapResponseBodyHandlerInterceptor.MODEL_NAME)) { + return model.get(CatnapResponseBodyHandlerInterceptor.MODEL_NAME); + } else { + return model.get(getModelName()); + } + } + } + + return null; + } + + @Override + public String getContentType() { + return catnapView.getContentType(); + } + + @Override + public String getCharacterEncoding() { + return catnapView.getEncoding(); + } + + @Override + public CatnapView getWrappedView() { + return catnapView; + } + + @Override + public String getModelName() { + return modelName; + } +} diff --git a/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/view/WrappingView.java b/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/view/WrappingView.java new file mode 100644 index 0000000..2586a77 --- /dev/null +++ b/catnap-springboot/src/main/java/com/github/gregwhitaker/catnap/springboot/view/WrappingView.java @@ -0,0 +1,41 @@ +/* + * Copyright 2016 Greg Whitaker + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.gregwhitaker.catnap.springboot.view; + +import com.github.gregwhitaker.catnap.core.view.CatnapView; + +/** + * Interface that links a {@link CatnapView} and a Spring {@link org.springframework.web.servlet.View} + * implementation. + */ +public interface WrappingView { + /** + * @return the underlying {@link CatnapView} implementation wrapped by this view. + */ + T getWrappedView(); + + /** + * @return the character encoding returned by the underlying {@link CatnapView} + * implementation wrapped by this view. (Ex. "UTF-8" or "UTF-16") + */ + String getCharacterEncoding(); + + /** + * @return name of the object in the {@link org.springframework.ui.Model} to render with Catnap. + */ + String getModelName(); +} diff --git a/gradle.properties b/gradle.properties index 9c29947..2ad5763 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ group=com.github.gregwhitaker -version=2.0.0 \ No newline at end of file +version=2.1.0 diff --git a/settings.gradle b/settings.gradle index 640e1e1..253f819 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,6 +3,7 @@ include 'catnap-core' include 'catnap-spring' include 'catnap-jaxrs' include 'catnap-examples' +include 'catnap-springboot' include 'catnap-examples:catnap-examples-springboot' findProject(':catnap-examples:catnap-examples-springboot')?.name = 'catnap-examples-springboot' include 'catnap-examples:catnap-examples-jersey' @@ -11,4 +12,3 @@ include 'catnap-examples:catnap-examples-springmvc' findProject(':catnap-examples:catnap-examples-springmvc')?.name = 'catnap-examples-springmvc' include 'catnap-examples:catnap-examples-resteasy' findProject(':catnap-examples:catnap-examples-resteasy')?.name = 'catnap-examples-resteasy' -