![JAR search and dependency download from the Maven repository](/logo.png)
play.api.rest.Rest Maven / Gradle / Ivy
The newest version!
package play.api.rest;
import brave.Tracer;
import brave.Tracing;
import com.google.common.collect.Maps;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import play.Configuration;
import play.api.rest.converter.jackson.JacksonConverterFactory;
import play.libs.concurrent.Promise;
import play.libs.transport.http.PromiseHttpClient;
import play.libs.transport.http.client.HttpClientFactory;
import play.libs.transport.http.client.IOType;
import scala.concurrent.ExecutionContext;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import static java.util.Collections.unmodifiableList;
@Singleton
public class Rest {
public static final Logger LOGGER = LoggerFactory.getLogger(Rest.class);
private final Map> serviceMethodCache = new ConcurrentHashMap<>();
private Tracer tracer;
private PromiseHttpClient callFactory;
private ExecutionContext callbackExecutor;
private RequestConfig requestConfig;
private String baseUrl;
private boolean validateEagerly;
private List converterFactories;
private Map,Object> apis = Maps.newConcurrentMap();
protected Rest(){}
@Inject
public Rest(Tracer tracer, Configuration conf){
PromiseHttpClient callFactory = HttpClientFactory.createHttpClient(IOType.ASYNC_NIO,conf);
String baseUrl = conf.getString("play.rest.base-url");
if(StringUtils.isBlank(baseUrl)){
baseUrl = resolveBaseUrl(conf);
}
// Make a defensive copy of the converters.
List converterFactories = new ArrayList<>();
converterFactories.add(new BuiltInConverters());
converterFactories.add(JacksonConverterFactory.create()); //默认使用Json进行转换
createRest(tracer,callFactory,baseUrl,converterFactories,null,false,null);
}
public Rest(Tracer tracer,PromiseHttpClient callFactory, String baseUrl, List converterFactories,ExecutionContext callbackExecutor, boolean validateEagerly,RequestConfig requestConfig) {
createRest(tracer,callFactory,baseUrl,converterFactories,callbackExecutor,validateEagerly,requestConfig);
}
private void createRest(Tracer tracer,PromiseHttpClient callFactory, String baseUrl, List converterFactories,ExecutionContext callbackExecutor, boolean validateEagerly,RequestConfig requestConfig) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = converterFactories;
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
this.requestConfig = requestConfig;
this.tracer = tracer;
if(this.tracer == null){
this.tracer = Tracing.newBuilder().build().tracer();
}
if(this.callFactory == null){
this.callFactory = HttpClientFactory.getHttpClient();
}
}
private String resolveBaseUrl(Configuration conf) {
return String.format("%s://%s:%s","http",conf.getString("play.server.http.address"),conf.getInt("play.server.http.port"));
}
/**
* Returns an unmodifiable list of the factories tried when creating a
* {@linkplain #requestBodyConverter(Type, Annotation[], Annotation[]) request body converter}, a
* {@linkplain #responseBodyConverter(Type, Annotation[]) response body converter}, or a
* {@linkplain #stringConverter(Type, Annotation[]) string converter}.
*/
public List converterFactories() {
return converterFactories;
}
/**
* Returns a {@link Converter} for {@code type} to {@link HttpEntity} from the available
* {@linkplain #converterFactories() factories}.
*
* @throws IllegalArgumentException if no converter available for {@code type}.
*/
public Converter requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations) {
return nextRequestBodyConverter(null, type, parameterAnnotations, methodAnnotations);
}
/**
* Returns a {@link Converter} for {@code type} to {@link HttpEntity} from the available
* {@linkplain #converterFactories() factories} except {@code skipPast}.
*
* @throws IllegalArgumentException if no converter available for {@code type}.
*/
public Converter nextRequestBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] parameterAnnotations,
Annotation[] methodAnnotations) {
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter.Factory factory = converterFactories.get(i);
Converter, HttpEntity> converter =
factory.requestBodyConverter(type, parameterAnnotations, methodAnnotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter) converter;
}
}
StringBuilder builder = new StringBuilder("Could not locate RequestBody converter for ")
.append(type)
.append(".\n");
if (skipPast != null) {
builder.append(" Skipped:");
for (int i = 0; i < start; i++) {
builder.append("\n * ").append(converterFactories.get(i).getClass().getName());
}
builder.append('\n');
}
builder.append(" Tried:");
for (int i = start, count = converterFactories.size(); i < count; i++) {
builder.append("\n * ").append(converterFactories.get(i).getClass().getName());
}
throw new IllegalArgumentException(builder.toString());
}
/**
* Returns a {@link Converter} for {@link HttpEntity} to {@code type} from the available
* {@linkplain #converterFactories() factories}.
*
* @throws IllegalArgumentException if no converter available for {@code type}.
*/
public Converter responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
/**
* Returns a {@link Converter} for {@link HttpEntity} to {@code type} from the available
* {@linkplain #converterFactories() factories} except {@code skipPast}.
*
* @throws IllegalArgumentException if no converter available for {@code type}.
*/
public Converter nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter) converter;
}
}
StringBuilder builder = new StringBuilder("Could not locate ResponseBody converter for ")
.append(type)
.append(".\n");
if (skipPast != null) {
builder.append(" Skipped:");
for (int i = 0; i < start; i++) {
builder.append("\n * ").append(converterFactories.get(i).getClass().getName());
}
builder.append('\n');
}
builder.append(" Tried:");
for (int i = start, count = converterFactories.size(); i < count; i++) {
builder.append("\n * ").append(converterFactories.get(i).getClass().getName());
}
throw new IllegalArgumentException(builder.toString());
}
/**
* Returns a {@link Converter} for {@code type} to {@link String} from the available
* {@linkplain #converterFactories() factories}.
*/
public Converter stringConverter(Type type, Annotation[] annotations) {
for (int i = 0, count = converterFactories.size(); i < count; i++) {
Converter, String> converter =
converterFactories.get(i).stringConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter) converter;
}
}
// Nothing matched. Resort to default converter which just calls toString().
//noinspection unchecked
return (Converter) BuiltInConverters.ToStringConverter.INSTANCE;
}
public String baseUrl() {
return this.baseUrl;
}
/**
* Create an implementation of the API endpoints defined by the {@code service} interface.
* For example:
*
* public interface CategoryService {
* @POST("category/{cat}/")
* Call<List<Item>> categoryList(@Path("cat") String a, @Query("page") int b);
* }
*
*/
@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
public T create(final Class service) {
T apiInst = (T)apis.get(service);
if(apiInst == null) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
final Rest rest = this;
apiInst = (T) Proxy.newProxyInstance(service.getClassLoader(), new Class>[]{service},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
/**
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}**/
ServiceMethod
© 2015 - 2025 Weber Informatics LLC | Privacy Policy