
com.jianggujin.http.support.JMethodHolder Maven / Gradle / Ivy
The newest version!
/**
* Copyright 2018 jianggujin (www.jianggujin.com).
*
* 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.jianggujin.http.support;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.net.Proxy;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import org.w3c.dom.Document;
import com.jianggujin.http.core.JHttpException;
import com.jianggujin.http.core.JMethod;
import com.jianggujin.http.core.JRequest;
import com.jianggujin.http.core.JRequestBodyResolver;
import com.jianggujin.http.core.JResponse;
import com.jianggujin.http.core.JSSLContextFactory;
import com.jianggujin.http.response.JByteBufferResponse;
import com.jianggujin.http.response.JByteResponse;
import com.jianggujin.http.response.JFileResponse;
import com.jianggujin.http.response.JNoBodyResponse;
import com.jianggujin.http.response.JTextResponse;
import com.jianggujin.http.response.JXMLDomResponse;
import com.jianggujin.http.support.annotation.JApiRequest;
import com.jianggujin.http.support.annotation.JApiRequestBodyResolver;
import com.jianggujin.http.support.annotation.JApiResponseCreator;
import com.jianggujin.http.support.annotation.JCookie;
import com.jianggujin.http.support.annotation.JHeader;
import com.jianggujin.http.support.annotation.JPathParam;
import com.jianggujin.http.support.annotation.JRequestBody;
import com.jianggujin.http.support.annotation.JRequestParam;
import com.jianggujin.http.util.JDataUtils;
import com.jianggujin.http.util.JKeyVal;
/**
* API方法数据持有类
*
* @author jianggujin
*
*/
public class JMethodHolder {
private static final int NOT_SET_POS = -1;
private String url;
private JApiRequestBodyResolver requestBodyResolver;
private JApiResponseCreator responseCreator;
private Map cookies;
private Map headers;
private Map requestParams;
private JApiRequest apiRequest;
private Method method;
private Class> returnClass;
private int responseIndex = NOT_SET_POS;
private int proxyIndex = NOT_SET_POS;
private int sslContextFactoryIndex = NOT_SET_POS;
private int requestBodyResolverIndex = NOT_SET_POS;
private int methodIndex = NOT_SET_POS;
private int[] keyValIndexs = {};
private JAnnotationHolder[] headerHolders = {};
private JAnnotationHolder[] cookieHolders = {};
private JAnnotationHolder[] requestParamHolders = {};
private JAnnotationHolder[] pathParamHolders = {};
private JAnnotationHolder requestBodyHolder = null;
protected JMethodHolder(String baseUrl, JApiRequestBodyResolver requestBodyResolver,
JApiResponseCreator responseCreator, Map cookies, Map headers,
Map requestParams, Method method)
throws JHttpException, InstantiationException, IllegalAccessException {
this.method = method;
this.apiRequest = method.getAnnotation(JApiRequest.class);
if (apiRequest == null) {
throw new JHttpException("target method not api.");
}
this.url = getUrl(baseUrl);
JApiRequestBodyResolver methodResolver = method.getAnnotation(JApiRequestBodyResolver.class);
this.requestBodyResolver = methodResolver != null ? methodResolver : requestBodyResolver;
JApiResponseCreator methodCreator = method.getAnnotation(JApiResponseCreator.class);
this.responseCreator = methodCreator != null ? methodCreator : responseCreator;
this.cookies = mixin(cookies, JApiInvocationHandler.getCookies(method.getAnnotation(JCookie.class)));
this.headers = mixin(headers, JApiInvocationHandler.getHeaders(method.getAnnotation(JHeader.class)));
this.requestParams = mixin(requestParams,
JApiInvocationHandler.getRequestParams(method.getAnnotation(JRequestParam.class)));
this.returnClass = method.getReturnType();
this.parseMethodParameter(method);
}
/**
* 获得请求地址
*
* @param baseUrl
* @return
*/
private String getUrl(String baseUrl) {
String urlPath = apiRequest.value();
String url = null;
if (baseUrl == null) {
url = urlPath;
} else {
url = baseUrl + urlPath;
}
return url;
}
/**
* 解析方法参数
*
* @param request
*/
private void parseMethodParameter(Method method) {
int pCount = method.getParameterCount();
if (pCount > 0) {
Class>[] pTypes = method.getParameterTypes();
Annotation[][] pAnnos = method.getParameterAnnotations();
int pos = 0;
for (Class> pType : pTypes) {
if (JResponse.class.isAssignableFrom(pType)) {
responseIndex = pos;
} else if (Proxy.class.isAssignableFrom(pType)) {
proxyIndex = pos;
} else if (JSSLContextFactory.class.isAssignableFrom(pType)) {
sslContextFactoryIndex = pos;
} else if (JRequestBodyResolver.class.isAssignableFrom(pType)) {
responseIndex = pos;
} else if (JMethod.class.isAssignableFrom(pType)) {
methodIndex = pos;
} else if (JKeyVal.class.isAssignableFrom(pType)) {
keyValIndexs = push(keyValIndexs, pos);
} else {
parseAnnotation(pType, pAnnos[pos], pos);
}
pos++;
}
}
}
/**
* 解析方法参数注解
*
* @param pType
* @param annotations
* @param pos
* @return
* @throws IOException
*/
private void parseAnnotation(Class> pType, Annotation[] annotations, int pos) {
if (annotations == null) {
return;
}
for (Annotation annotation : annotations) {
if (annotation instanceof JHeader) {// 处理请求头
JHeader header = (JHeader) annotation;
JAnnotationHolder holder = parseAnnotation(header.value(), header.required(), pType, pos, "header");
this.headerHolders = push(this.headerHolders, holder);
}
if (annotation instanceof JPathParam) {// 处理路径参数
JPathParam pathParam = (JPathParam) annotation;
JAnnotationHolder holder = parseAnnotation(pathParam.value(), pathParam.required(), pType, pos,
"pathParam");
this.pathParamHolders = push(this.pathParamHolders, holder);
}
if (annotation instanceof JRequestBody) {// 处理请求体
JRequestBody requestBody = (JRequestBody) annotation;
this.requestBodyHolder = new JAnnotationHolder(true, null, requestBody.required(), pos);
}
if (annotation instanceof JRequestParam) {// 处理请求参数
JRequestParam requestParam = (JRequestParam) annotation;
JAnnotationHolder holder = parseAnnotation(requestParam.value(), requestParam.required(), pType, pos,
"requestParam");
this.requestParamHolders = push(this.requestParamHolders, holder);
}
if (annotation instanceof JCookie) {// 处理Cookie
JCookie header = (JCookie) annotation;
JAnnotationHolder holder = parseAnnotation(header.value(), header.required(), pType, pos, "cookie");
this.cookieHolders = push(this.cookieHolders, holder);
}
}
}
/**
* 解析方法参数注解
*
* @param value
* @param required
* @param pType
* @param pos
* @param annType
* @return
*/
private JAnnotationHolder parseAnnotation(String value, boolean required, Class> pType, int pos, String annType) {
JAnnotationHolder holder = null;
if (String.class.equals(pType)) {
if (JDataUtils.isEmpty(value)) {
throw new IllegalArgumentException("method " + annType + " annotation, value must not be empty.");
}
holder = new JAnnotationHolder(true, value, required, pos);
} else if (Map.class.isAssignableFrom(pType)) {// Map
holder = new JAnnotationHolder(false, value, required, pos);
} else {
throw new IllegalArgumentException("method " + annType + " annotation parameter type not support.");
}
return holder;
}
/**
* 执行请求
*
* @param args
* @return
* @throws JHttpException
* @throws IllegalAccessException
* @throws InstantiationException
*/
public Object invoke(Object[] args) throws InstantiationException, IllegalAccessException, JHttpException {
JRequest request = JRequest.create((URL) null).method(apiRequest.method()).ignoreError(apiRequest.ignoreError())
.charset(apiRequest.charset()).forceHasBody(apiRequest.forceHasBody()).timeout(apiRequest.timeout())
.cookie(cookies).header(headers).data(requestParams);
if (this.requestBodyResolver != null) {
JRequestBodyResolver resolver = JApiInvocationHandler.getRequestBodyResolver(this.requestBodyResolver);
if (resolver != null) {
request.requestBodyResolver();
}
}
initRequestWithMethodParameter(request, args);
request.url(buildUrl(args));
// 处理默认响应
JResponse response = request.response();
// 判断是否需要设置响应对象
autoSetResponse(request);
response = request.execute().response();
// 处理方法实际的返回数据
if (response != null) {
Object result = response.getData();
if (result != null && returnClass.isAssignableFrom(result.getClass())) {
return result;
}
if (returnClass.isAssignableFrom(response.getClass())) {
return response;
}
}
return null;
}
/**
* 根据方法参数初始化请求对象
*
* @param request
* @param args
*/
@SuppressWarnings("unchecked")
private void initRequestWithMethodParameter(JRequest request, Object[] args) {
if (responseIndex != NOT_SET_POS) {
request.response((JResponse) args[responseIndex]);
}
if (proxyIndex != NOT_SET_POS) {
request.proxy((Proxy) args[proxyIndex]);
}
if (sslContextFactoryIndex != NOT_SET_POS) {
request.sslContextFactory((JSSLContextFactory) args[sslContextFactoryIndex]);
}
if (requestBodyResolverIndex != NOT_SET_POS) {
request.requestBodyResolver((JRequestBodyResolver) args[requestBodyResolverIndex]);
}
if (methodIndex != NOT_SET_POS) {
request.method((JMethod) args[methodIndex]);
}
for (int pos : keyValIndexs) {
request.data((JKeyVal) args[pos]);
}
for (JAnnotationHolder holder : headerHolders) {
if (holder.isSingle()) {
if (holder.isRequired() && args[holder.getPos()] == null) {
throw new IllegalArgumentException("method header annotation requried parameter must not be null.");
}
request.header(holder.getName(), (String) args[holder.getPos()]);
} else {
request.header((Map) args[holder.getPos()]);
}
}
for (JAnnotationHolder holder : cookieHolders) {
if (holder.isSingle()) {
if (holder.isRequired() && args[holder.getPos()] == null) {
throw new IllegalArgumentException("method cookie annotation requried parameter must not be null.");
}
request.cookie(holder.getName(), (String) args[holder.getPos()]);
} else {
request.cookie((Map) args[holder.getPos()]);
}
}
for (JAnnotationHolder holder : requestParamHolders) {
if (holder.isSingle()) {
if (holder.isRequired() && args[holder.getPos()] == null) {
throw new IllegalArgumentException(
"method requestParam annotation requried parameter must not be null.");
}
request.data(holder.getName(), (String) args[holder.getPos()]);
} else {
request.data((Map) args[holder.getPos()]);
}
}
if (requestBodyHolder != null) {
if (requestBodyHolder.isRequired() && args[requestBodyHolder.getPos()] == null) {
throw new IllegalArgumentException(
"method requestBody annotation requried parameter must not be null.");
}
request.requestBody(args[requestBodyHolder.getPos()]);
}
}
/**
* 构建请求地址
*
* @param args
* @return
*/
@SuppressWarnings("unchecked")
private String buildUrl(Object[] args) {
// 存在路径参数,需要处理
if (pathParamHolders.length > 0) {
Map pathParams = new HashMap();
for (JAnnotationHolder holder : pathParamHolders) {
if (holder.isSingle()) {
if (holder.isRequired() && args[holder.getPos()] == null) {
throw new IllegalArgumentException(
"method pathParam annotation requried parameter must not be null.");
}
pathParams.put(holder.getName(), (String) args[holder.getPos()]);
} else {
pathParams.putAll((Map) args[holder.getPos()]);
}
}
return JDataUtils.resolveDynamicPropnames(url, pathParams, "{", "}");
} else {
return url;
}
}
/**
* 自动设置响应对象
*
* @param request
* @throws InstantiationException
* @throws IllegalAccessException
* @throws JHttpException
*/
private void autoSetResponse(JRequest request)
throws InstantiationException, IllegalAccessException, JHttpException {
JResponse response = request.response();
// 未设置响应对象
if (response == null) {
if (this.responseCreator != null) {
JResponseCreator creator = JApiInvocationHandler.getResponseCreator(this.responseCreator);
if (creator != null) {
response = creator.create(request, method);
}
} else if (String.class.equals(returnClass)) {
response = new JTextResponse();
} else if (byte[].class.equals(returnClass)) {
response = new JByteResponse();
} else if (ByteBuffer.class.equals(returnClass)) {
response = new JByteBufferResponse();
} else if (File.class.equals(returnClass)) {
response = new JFileResponse();
} else if (Document.class.equals(returnClass)) {
response = new JXMLDomResponse();
} else {
response = new JNoBodyResponse();
}
request.response(response);
}
}
private static int[] push(int[] is, int i) {
int len = is.length;
int[] tmp = new int[len + 1];
System.arraycopy(is, 0, tmp, 0, len);
tmp[len] = i;
return tmp;
}
private static JAnnotationHolder[] push(JAnnotationHolder[] hs, JAnnotationHolder holder) {
int len = hs.length;
JAnnotationHolder[] tmp = new JAnnotationHolder[len + 1];
System.arraycopy(hs, 0, tmp, 0, len);
tmp[len] = holder;
return tmp;
}
/**
* 混合两个Map
*
* @param map1
* @param map2
* @return
*/
private static Map mixin(Map map1, Map map2) {
if (map1 == null) {
return map2;
}
if (map2 == null) {
return map1;
}
map1.putAll(map2);
return map1;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy