Skip to content

Commit

Permalink
Spring FastJsonHttpMessageConverter
Browse files Browse the repository at this point in the history
Support ParamterizedType and TypeVariable
  • Loading branch information
neil4dong committed Aug 5, 2017
1 parent 31fbdc0 commit 628207f
Show file tree
Hide file tree
Showing 6 changed files with 398 additions and 199 deletions.
Expand Up @@ -7,6 +7,7 @@
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.util.IOUtils;
import org.springframework.core.ResolvableType;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
Expand All @@ -19,7 +20,9 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -171,7 +174,7 @@ public Object read(Type type, //
Class<?> contextClass, //
HttpInputMessage inputMessage //
) throws IOException, HttpMessageNotReadableException {
return readType(type, inputMessage);
return readType(getType(type, contextClass), inputMessage);
}

/*
Expand All @@ -190,8 +193,7 @@ public void write(Object o, Type type, MediaType contentType, HttpOutputMessage
protected Object readInternal(Class<? extends Object> clazz, //
HttpInputMessage inputMessage //
) throws IOException, HttpMessageNotReadableException {

return readType(clazz, inputMessage);
return readType(getType(clazz, null), inputMessage);
}

private Object readType(Type type, HttpInputMessage inputMessage) throws IOException {
Expand Down Expand Up @@ -312,4 +314,64 @@ protected int writeSuffix(ByteArrayOutputStream out, Object object) throws IOExc
}


protected Type getType(Type type, Class<?> contextClass) {
if(contextClass != null) {
ResolvableType resolvedType = ResolvableType.forType(type);
if(type instanceof TypeVariable) {
ResolvableType resolvedTypeVariable = this.resolveVariable((TypeVariable)type, ResolvableType.forClass(contextClass));
if(resolvedTypeVariable != ResolvableType.NONE) {
return resolvedTypeVariable.resolve();
}
} else if(type instanceof ParameterizedType && resolvedType.hasUnresolvableGenerics()) {
ParameterizedType parameterizedType = (ParameterizedType)type;
Class<?>[] generics = new Class[parameterizedType.getActualTypeArguments().length];
Type[] typeArguments = parameterizedType.getActualTypeArguments();

for(int i = 0; i < typeArguments.length; ++i) {
Type typeArgument = typeArguments[i];
if(typeArgument instanceof TypeVariable) {
ResolvableType resolvedTypeArgument = this.resolveVariable((TypeVariable)typeArgument, ResolvableType.forClass(contextClass));
if(resolvedTypeArgument != ResolvableType.NONE) {
generics[i] = resolvedTypeArgument.resolve();
} else {
generics[i] = ResolvableType.forType(typeArgument).resolve();
}
} else {
generics[i] = ResolvableType.forType(typeArgument).resolve();
}
}

return ResolvableType.forClassWithGenerics(resolvedType.getRawClass(), generics).getType();
}
}

return type;
}

private ResolvableType resolveVariable(TypeVariable<?> typeVariable, ResolvableType contextType) {
ResolvableType resolvedType;
if (contextType.hasGenerics()) {
resolvedType = ResolvableType.forType(typeVariable, contextType);
if (resolvedType.resolve() != null) {
return resolvedType;
}
}

ResolvableType superType = contextType.getSuperType();
if (superType != ResolvableType.NONE) {
resolvedType = resolveVariable(typeVariable, superType);
if (resolvedType.resolve() != null) {
return resolvedType;
}
}
for (ResolvableType ifc : contextType.getInterfaces()) {
resolvedType = resolveVariable(typeVariable, ifc);
if (resolvedType.resolve() != null) {
return resolvedType;
}
}
return ResolvableType.NONE;
}


}
172 changes: 172 additions & 0 deletions src/test/java/com/alibaba/json/bvt/issue_1300/Issue1341.java
@@ -0,0 +1,172 @@
package com.alibaba.json.bvt.issue_1300;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONPObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.jaxrs.FastJsonProvider;
import org.glassfish.jersey.CommonProperties;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.internal.InternalProperties;
import org.glassfish.jersey.internal.util.PropertiesHelper;
import org.glassfish.jersey.server.JSONP;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.TestProperties;
import org.junit.Assert;
import org.junit.Test;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Configuration;
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import java.util.Date;

import static org.junit.Assert.assertTrue;

public class Issue1341 extends JerseyTest {
static class Book {

private int bookId;
private String bookName;
private String publisher;
private String isbn;
private Date publishTime;
private Object hello;

public int getBookId() {
return bookId;
}

public void setBookId(int bookId) {
this.bookId = bookId;
}

public String getBookName() {
return bookName;
}

public void setBookName(String bookName) {
this.bookName = bookName;
}

public String getPublisher() {
return publisher;
}

public void setPublisher(String publisher) {
this.publisher = publisher;
}

public String getIsbn() {
return isbn;
}

public void setIsbn(String isbn) {
this.isbn = isbn;
}

public Date getPublishTime() {
return publishTime;
}

public void setPublishTime(Date publishTime) {
this.publishTime = publishTime;
}

public Object getHello() {
return hello;
}

public void setHello(Object hello) {
this.hello = hello;
}
}

static class FastJsonFeature implements Feature {

private final static String JSON_FEATURE = FastJsonFeature.class.getSimpleName();

public boolean configure(final FeatureContext context) {
final Configuration config = context.getConfiguration();
final String jsonFeature = CommonProperties.getValue(config.getProperties(), config.getRuntimeType(), InternalProperties.JSON_FEATURE, JSON_FEATURE,
String.class);
// Other JSON providers registered.
if (!JSON_FEATURE.equalsIgnoreCase(jsonFeature)) {
return false;
}
// Disable other JSON providers.
context.property(PropertiesHelper.getPropertyNameForRuntime(InternalProperties.JSON_FEATURE, config.getRuntimeType()), JSON_FEATURE);
// Register FastJson.
if (!config.isRegistered(FastJsonProvider.class)) {
//DisableCircularReferenceDetect
FastJsonProvider fastJsonProvider = new FastJsonProvider();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
//fastJsonConfig.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect,SerializerFeature.BrowserSecure);

fastJsonConfig.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);

fastJsonProvider.setFastJsonConfig(fastJsonConfig);

context.register(fastJsonProvider, MessageBodyReader.class, MessageBodyWriter.class);
}
return true;
}
}


@Path("book")
public static class BookRestFul {

@GET
@Path("{id}")
@Produces({"application/javascript", "application/json"})
@JSONP(queryParam = "callback")
public Book getBookById(@PathParam("id") Long id) {

Book book = new Book();
book.setBookId(2);
book.setBookName("Python源码剖析");
book.setPublisher("电子工业出版社");
book.setPublishTime(new Date());
book.setIsbn("911122");

return book;
}
}

@Override
protected void configureClient(ClientConfig config) {
config.register(new FastJsonFeature()).register(FastJsonProvider.class);
}

@Override
protected Application configure() {
enable(TestProperties.LOG_TRAFFIC);
enable(TestProperties.DUMP_ENTITY);

ResourceConfig config = new ResourceConfig();

config.register(new FastJsonFeature()).register(FastJsonProvider.class);
config.packages("com.alibaba.json");
return config;
}

@Test
public void test() {

final String reponse = target("book").path("123").request().accept("application/javascript").get(String.class);

Assert.assertTrue(reponse.indexOf("Python源码剖析") > 0);
Assert.assertTrue(reponse.indexOf("电子工业出版社") > 0);
Assert.assertTrue(reponse.indexOf("\"hello\":null") > 0);
}

}

0 comments on commit 628207f

Please sign in to comment.