Skip to content

Commit

Permalink
Merge pull request #151 from swagger-api/issue-150
Browse files Browse the repository at this point in the history
added `enableType` on processor interface
  • Loading branch information
fehguy authored Sep 20, 2016
2 parents db63342 + 3b60c58 commit 5dcb2b6
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 34 deletions.
34 changes: 22 additions & 12 deletions src/main/java/io/swagger/inflector/SwaggerInflector.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,7 @@
import io.swagger.inflector.converters.Converter;
import io.swagger.inflector.converters.InputConverter;
import io.swagger.inflector.models.InflectResult;
import io.swagger.inflector.processors.JsonExampleProvider;
import io.swagger.inflector.processors.JsonNodeExampleSerializer;
import io.swagger.inflector.processors.JsonProvider;
import io.swagger.inflector.processors.XMLExampleProvider;
import io.swagger.inflector.processors.YamlExampleProvider;
import io.swagger.inflector.processors.*;
import io.swagger.inflector.utils.DefaultContentTypeProvider;
import io.swagger.inflector.utils.DefaultSpecFilter;
import io.swagger.inflector.utils.ResolverUtil;
Expand All @@ -53,18 +49,12 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import javax.servlet.ServletContext;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import java.util.*;

public class SwaggerInflector extends ResourceConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(SwaggerInflector.class);
Expand Down Expand Up @@ -194,19 +184,22 @@ protected void init(Configuration configuration) {
register(new DefaultContentTypeProvider(MediaType.APPLICATION_JSON_TYPE),
ContextResolver.class);
}
enableProcessor(JacksonProcessor.class, MediaType.APPLICATION_JSON_TYPE);
enableSwaggerJSON(swagger, configuration.getSwaggerProcessors());
} else if ("xml".equalsIgnoreCase(item)) {
// XML
if (!isRegistered(DefaultContentTypeProvider.class)) {
register(new DefaultContentTypeProvider(MediaType.APPLICATION_XML_TYPE),
ContextResolver.class);
}
enableProcessor(JacksonProcessor.class, MediaType.APPLICATION_XML_TYPE);
register(JacksonJaxbXMLProvider.class);
register(XMLExampleProvider.class);
} else if ("yaml".equalsIgnoreCase(item)) {
// YAML
Yaml.mapper().registerModule(simpleModule);
register(YamlExampleProvider.class);
enableProcessor(JacksonProcessor.class, JacksonProcessor.APPLICATION_YAML_TYPE);
enableSwaggerYAML(swagger, configuration.getSwaggerProcessors());
}
}
Expand Down Expand Up @@ -332,6 +325,23 @@ private String basePath(String basePath, String path) {
return basePath + path;
}

private void enableProcessor(Class<?> cls, MediaType type) {
List<EntityProcessor> processors = EntityProcessorFactory.getProcessors();
for(EntityProcessor processor : processors) {
if (processor.getClass().equals(cls)) {
processor.enableType(type);
return;
}
}
try {
EntityProcessor processor = (EntityProcessor) cls.newInstance();
processor.enableType(type);
}
catch (Exception e) {
LOGGER.error("unable to initialize class " + cls);
}
}

private void enableSwaggerJSON(Swagger swagger, List<String> swaggerProcessors) {
final Resource.Builder builder = Resource.builder();
builder.path(basePath(originalBasePath, config.getSwaggerBase() + "swagger.json"))
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/io/swagger/inflector/config/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ public class Configuration {
private Set<Direction> validatePayloads = Collections.emptySet();

public String getSwaggerBase() {
if("".equals(swaggerBase) || "/".equals(swaggerBase)) {
return swaggerBase;
}

if(swaggerBase != null) {
if(swaggerBase.endsWith("/")) {
return swaggerBase.substring(0, swaggerBase.length() - 1);
}
}
return swaggerBase;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -607,28 +607,35 @@ else if(output instanceof ObjectExample) {
// get acceptable content types
List<EntityProcessor> processors = EntityProcessorFactory.getProcessors();

MediaType responseMediaType = null;

// take first compatible one
for (EntityProcessor processor : processors) {
if(responseMediaType != null) {
break;
}
for (MediaType mt : requestContext.getAcceptableMediaTypes()) {
LOGGER.debug("checking type " + mt.toString() + " against " + processor.getClass().getName());
if (processor.supports(mt)) {
builder.type(mt);
responseMediaType = mt;
break;
}
}
}

// no match based on Accept header, use first processor in list
for (EntityProcessor processor : processors) {
List<MediaType> supportedTypes = processor.getSupportedMediaTypes();
if(supportedTypes.size() > 0) {
builder.type(supportedTypes.get(0));
break;
if(responseMediaType == null) {
// no match based on Accept header, use first processor in list
for (EntityProcessor processor : processors) {
List<MediaType> supportedTypes = processor.getSupportedMediaTypes();
if (supportedTypes.size() > 0) {
builder.type(supportedTypes.get(0));
break;
}
}
}
}


builder.entity(output);
}
return builder.build();
Expand Down
20 changes: 16 additions & 4 deletions src/main/java/io/swagger/inflector/processors/BinaryProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,26 @@
import java.util.List;

public class BinaryProcessor implements EntityProcessor {

private static final Logger LOGGER = LoggerFactory.getLogger(BinaryProcessor.class);
private static List<MediaType> SUPPORTED_TYPES = new ArrayList<>();

static {
SUPPORTED_TYPES.add(MediaType.APPLICATION_OCTET_STREAM_TYPE);
}

@Override
public List<MediaType> getSupportedMediaTypes() {
List<MediaType> supportedTypes = new ArrayList<>();
supportedTypes.add(MediaType.APPLICATION_OCTET_STREAM_TYPE);
return supportedTypes;
return new ArrayList(SUPPORTED_TYPES);
}

@Override
public void enableType(MediaType type) {
MediaType t = type;
if(t != null) {
if(!SUPPORTED_TYPES.contains(t)) {
SUPPORTED_TYPES.add(type);
}
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public interface EntityProcessor {

List<MediaType> getSupportedMediaTypes();

void enableType(MediaType type);

Object process(MediaType mediaType, InputStream entityStream, Class<?> cls) throws ConversionException;

Object process(MediaType mediaType, InputStream entityStream, JavaType javaType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@
package io.swagger.inflector.processors;

import io.swagger.inflector.converters.ConversionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.core.MediaType;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class EntityProcessorFactory {
private static final Logger LOGGER = LoggerFactory.getLogger(EntityProcessorFactory.class);

private static List<EntityProcessor> PROCESSORS = new ArrayList<EntityProcessor>();

static {
Expand All @@ -32,8 +36,21 @@ public class EntityProcessorFactory {
PROCESSORS.add(new BinaryProcessor());
}

public static void addProcessor(EntityProcessor processor) {
PROCESSORS.add(processor);
public static void addProcessor(Class<?> cls, MediaType type) {
for(EntityProcessor entityProcessor : PROCESSORS) {
if(entityProcessor.getClass().equals(cls)) {
entityProcessor.enableType(type);
return;
}
}
try {
EntityProcessor processor = (EntityProcessor) cls.newInstance();
PROCESSORS.add(processor);
processor.enableType(type);
}
catch (Exception e) {
LOGGER.debug("unable to add processor " + cls.getName());
}
}

public static Object readValue(MediaType mediaType, InputStream entityStream, Class<?> class1) throws ConversionException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,31 @@
public class JacksonProcessor implements EntityProcessor {
private static final Logger LOGGER = LoggerFactory.getLogger(JacksonProcessor.class);

public static MediaType APPLICATION_YAML_TYPE = new MediaType("application", "yaml");

private static XmlMapper XML = new XmlMapper();
private static MediaType APPLICATION_YAML = new MediaType("application", "yaml");
private static Collection<MediaType> SUPPORTED_TYPES = Collections
.unmodifiableList(Arrays.asList(MediaType.APPLICATION_JSON_TYPE,
MediaType.APPLICATION_XML_TYPE, APPLICATION_YAML, MediaType.TEXT_PLAIN_TYPE));
private static List<MediaType> SUPPORTED_TYPES = new ArrayList<>();

static {
SUPPORTED_TYPES.add(MediaType.APPLICATION_JSON_TYPE);
}

@Override
public List<MediaType> getSupportedMediaTypes() {
return new ArrayList(SUPPORTED_TYPES);
}

@Override
public void enableType(MediaType type) {
if(!SUPPORTED_TYPES.contains(type)) {
SUPPORTED_TYPES.add(type);
}
}

@Override
public boolean supports(MediaType mediaType) {
for (MediaType item : SUPPORTED_TYPES) {
if (item.isCompatible(mediaType)) {
if (item.isCompatible(mediaType) && !mediaType.isWildcardType()) {
return true;
}
}
Expand All @@ -68,7 +78,7 @@ public Object process(MediaType mediaType, InputStream entityStream,
if (MediaType.APPLICATION_XML_TYPE.isCompatible(mediaType)) {
return XML.readValue(entityStream, javaType);
}
if (APPLICATION_YAML.isCompatible(mediaType)) {
if (APPLICATION_YAML_TYPE.isCompatible(mediaType)) {
return Yaml.mapper().readValue(entityStream, javaType);
}
} catch (IOException e) {
Expand All @@ -92,7 +102,7 @@ public Object process(MediaType mediaType, InputStream entityStream, Class<?> cl
if (MediaType.APPLICATION_XML_TYPE.isCompatible(mediaType)) {
return XML.readValue(entityStream, cls);
}
if (APPLICATION_YAML.isCompatible(mediaType)) {
if (APPLICATION_YAML_TYPE.isCompatible(mediaType)) {
return Yaml.mapper().readValue(entityStream, cls);
}
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package io.swagger.inflector.utils;

import io.swagger.inflector.models.ApiError;
import io.swagger.inflector.processors.EntityProcessor;
import io.swagger.inflector.processors.EntityProcessorFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -30,6 +32,7 @@
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.Providers;
import java.util.List;

@Provider
public class DefaultExceptionMapper implements ExceptionMapper<Exception> {
Expand All @@ -50,9 +53,45 @@ public Response toResponse(Exception exception) {
}
} else {
LOGGER.error(error.getMessage(), exception);
} final Response.ResponseBuilder builder = Response.status(code).entity(error);
}

final Response.ResponseBuilder builder = Response.status(code).entity(error);

MediaType responseMediaType = null;
List<EntityProcessor> processors = EntityProcessorFactory.getProcessors();
for (EntityProcessor processor : processors) {
if(responseMediaType != null) {
break;
}
for (MediaType mt : headers.getAcceptableMediaTypes()) {
LOGGER.debug("checking type " + mt.toString() + " against " + processor.getClass().getName());
if (processor.supports(mt)) {
builder.type(mt);
responseMediaType = mt;
break;
}
}
}

if(responseMediaType == null) {
// no match based on Accept header, use first processor in list
for (EntityProcessor processor : processors) {
List<MediaType> supportedTypes = processor.getSupportedMediaTypes();
if (supportedTypes.size() > 0) {
MediaType mt = supportedTypes.get(0);
builder.type(mt);
responseMediaType = mt;
break;
}
}
}

if(responseMediaType == null) {
responseMediaType = MediaType.WILDCARD_TYPE;
}

final ContextResolver<ContentTypeSelector> selector = providers.getContextResolver(
ContentTypeSelector.class, MediaType.WILDCARD_TYPE);
ContentTypeSelector.class, responseMediaType);
if (selector != null) {
selector.getContext(getClass()).apply(headers.getAcceptableMediaTypes(), builder);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.inflector.processors.EntityProcessorFactory;
import io.swagger.inflector.processors.JacksonProcessor;
import org.testng.annotations.Test;

import javax.ws.rs.core.MediaType;
Expand All @@ -33,6 +34,8 @@ public class JacksonProcessorTest {
public void testConvertXMLContent() throws Exception {
String input = "<user><id>1</id><name>fehguy</name></user>";

EntityProcessorFactory.addProcessor(JacksonProcessor.class, MediaType.APPLICATION_XML_TYPE);

InputStream is = new ByteArrayInputStream(input.getBytes());
ObjectNode o = (ObjectNode) EntityProcessorFactory.readValue(MediaType.APPLICATION_XML_TYPE, is, JsonNode.class);
assertEquals(o.getClass(), ObjectNode.class);
Expand All @@ -42,6 +45,7 @@ public void testConvertXMLContent() throws Exception {
@Test
public void testConvertJsonContent() throws Exception {
String input = "{\"name\":\"fehguy\"}";
EntityProcessorFactory.addProcessor(JacksonProcessor.class, MediaType.APPLICATION_JSON_TYPE);

InputStream is = new ByteArrayInputStream(input.getBytes());
ObjectNode o = (ObjectNode) EntityProcessorFactory.readValue(MediaType.APPLICATION_JSON_TYPE, is, JsonNode.class);
Expand All @@ -52,6 +56,7 @@ public void testConvertJsonContent() throws Exception {
@Test
public void testConvertYamlContent() throws Exception {
String input = "name: fehguy\nuserId: 42";
EntityProcessorFactory.addProcessor(JacksonProcessor.class, JacksonProcessor.APPLICATION_YAML_TYPE);

InputStream is = new ByteArrayInputStream(input.getBytes());
MediaType t = MediaType.valueOf("application/yaml");
Expand Down

0 comments on commit 5dcb2b6

Please sign in to comment.