From ba08cf4b192a4b593cc09f18ab44111b0b5bdeec Mon Sep 17 00:00:00 2001
From: Daniel Gerhardt <code@dgerhardt.net>
Date: Sat, 27 Jan 2018 16:44:19 +0100
Subject: [PATCH] Add custom ContentNegotiationStrategy as fallback

PathApiVersionContentNegotiationStrategy selects the media type based on
request path. It allows to set the correct media type for old clients
which do not set the 'Accept' header.
---
 .../java/de/thm/arsnova/config/AppConfig.java |  8 +++-
 ...hApiVersionContentNegotiationStrategy.java | 46 +++++++++++++++++++
 2 files changed, 52 insertions(+), 2 deletions(-)
 create mode 100644 src/main/java/de/thm/arsnova/web/PathApiVersionContentNegotiationStrategy.java

diff --git a/src/main/java/de/thm/arsnova/config/AppConfig.java b/src/main/java/de/thm/arsnova/config/AppConfig.java
index 287c5772c..4d8f3f782 100644
--- a/src/main/java/de/thm/arsnova/config/AppConfig.java
+++ b/src/main/java/de/thm/arsnova/config/AppConfig.java
@@ -27,6 +27,7 @@ import de.thm.arsnova.connector.client.ConnectorClient;
 import de.thm.arsnova.connector.client.ConnectorClientImpl;
 import de.thm.arsnova.entities.serialization.CouchDbDocumentModule;
 import de.thm.arsnova.entities.serialization.View;
+import de.thm.arsnova.web.PathApiVersionContentNegotiationStrategy;
 import de.thm.arsnova.websocket.ArsnovaSocketioServer;
 import de.thm.arsnova.websocket.ArsnovaSocketioServerImpl;
 import de.thm.arsnova.websocket.ArsnovaSocketioServerListener;
@@ -127,11 +128,14 @@ public class AppConfig extends WebMvcConfigurerAdapter {
 
 	@Override
 	public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
+		PathApiVersionContentNegotiationStrategy strategy =
+				new PathApiVersionContentNegotiationStrategy(API_V3_MEDIA_TYPE);
 		configurer.mediaType("json", MediaType.APPLICATION_JSON_UTF8);
 		configurer.mediaType("xml", MediaType.APPLICATION_XML);
-		configurer.defaultContentType(API_V3_MEDIA_TYPE);
-		configurer.favorParameter(true);
+		configurer.favorParameter(false);
 		configurer.favorPathExtension(false);
+		//configurer.defaultContentType(API_V3_MEDIA_TYPE);
+		configurer.defaultContentTypeStrategy(strategy);
 	}
 
 	@Override
diff --git a/src/main/java/de/thm/arsnova/web/PathApiVersionContentNegotiationStrategy.java b/src/main/java/de/thm/arsnova/web/PathApiVersionContentNegotiationStrategy.java
new file mode 100644
index 000000000..83e417d19
--- /dev/null
+++ b/src/main/java/de/thm/arsnova/web/PathApiVersionContentNegotiationStrategy.java
@@ -0,0 +1,46 @@
+package de.thm.arsnova.web;
+
+import de.thm.arsnova.config.AppConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.MediaType;
+import org.springframework.web.HttpMediaTypeNotAcceptableException;
+import org.springframework.web.accept.ContentNegotiationStrategy;
+import org.springframework.web.context.request.NativeWebRequest;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This {@link ContentNegotiationStrategy} selects the media type based on request path. It allows to set the correct
+ * media type for old clients which do not set the 'Accept' header.
+ *
+ * @author Daniel Gerhardt
+ */
+public class PathApiVersionContentNegotiationStrategy implements ContentNegotiationStrategy {
+	private static final Logger logger = LoggerFactory.getLogger(PathApiVersionContentNegotiationStrategy.class);
+
+	private MediaType fallback;
+
+	public PathApiVersionContentNegotiationStrategy(MediaType fallback) {
+		this.fallback = fallback;
+	}
+
+	@Override
+	public List<MediaType> resolveMediaTypes(final NativeWebRequest webRequest)
+			throws HttpMediaTypeNotAcceptableException {
+		final HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
+		final List<MediaType> mediaTypes = new ArrayList<>();
+		if (servletRequest.getServletPath().startsWith("/v2/")) {
+			logger.trace("Negotiating content based on path for API v2");
+			mediaTypes.add(AppConfig.API_V2_MEDIA_TYPE);
+			mediaTypes.add(MediaType.TEXT_PLAIN);
+		} else {
+			logger.trace("Content negotiation falling back to {}", fallback);
+			mediaTypes.add(fallback);
+		}
+
+		return mediaTypes;
+	}
+}
-- 
GitLab