cxfUtil代码实现类
package
import gboat2.base.bridge.exception.DefaultGboatNestedException;
import .util.json.JsonUtil;
import .util.xml.JAXBUtil;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.namespace.QName;
import javax.xml.xpath.XPathFactory;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.WordUtils;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.common.jaxb.JAXBUtils;
import org.apache.cxf.common.jaxb.JAXBUtils.IdentifierType;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.service.model.BindingInfo;
import org.apache.cxf.service.model.BindingMessageInfo;
import org.apache.cxf.service.model.BindingOperationInfo;
import org.apache.cxf.service.model.MessagePartInfo;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.util.Assert;
import com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl;
@SuppressWarnings("restriction")
public class CXFUtil {
private final static Logger logger = LoggerFactory.getLogger(CXFUtil.class);
private final static int CONFIGURE_CLIENT_SIZE = 999999999;
static {
// 设置 XPathFactory,解决调用 webService 传递复杂对象时抛出 java.lang.ExceptionInInitializerError 错误的问题
System.setProperty(XPathFactory.DEFAULT_PROPERTY_NAME + ":" + XPathFactory.DEFAULT_OBJECT_MODEL_URI,
XPathFactoryImpl.class.getName());
}
private CXFUtil() {
}
public static Client createJaxWsDynamicClient(String wsdlUrl){
return createJaxWsDynamicClient(wsdlUrl, JaxWsDynamicClientFactory.class.getClassLoader());
}
public static Client createJaxWsDynamicClient(String wsdlUrl, AuthorityParameter authorityParameter){
return createJaxWsDynamicClient(wsdlUrl, authorityParameter, null);
}
public static Client createJaxWsDynamicClient(String wsdlUrl, ClassLoader classLoader) {
return createJaxWsDynamicClient(wsdlUrl, null, classLoader);
}
public static Client createJaxWsDynamicClient(String wsdlUrl, AuthorityParameter authorityParameter, ClassLoader classLoader) {
// 创建 HttpClient 策略
HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setAllowChunking(false);
httpClientPolicy.setChunkingThreshold(CONFIGURE_CLIENT_SIZE);
// 动态创建 WebService 客户端
Client client = GboatJaxWsDynamicClientFactory.newInstance().createClient(wsdlUrl, classLoader);
// 设置用户名密码
if(null != authorityParameter) {
client.getOutInterceptors().add(new AuthorityHeaderInterceptor(authorityParameter));
client.getOutInterceptors().add(new LoggingOutInterceptor());
}
((HTTPConduit) client.getConduit()).setClient(httpClientPolicy);
return client;
}
public static Client createJaxWsDynamicClient(String wsdlUrl, AbstractPhaseInterceptor<SoapMessage> interceptor) {
// 创建 HttpClient 策略
HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setAllowChunking(false);
httpClientPolicy.setChunkingThreshold(CONFIGURE_CLIENT_SIZE);
// 动态创建 WebService 客户端
Client client = GboatJaxWsDynamicClientFactory.newInstance().createClient(wsdlUrl);
// 设置用户名密码
if(null != interceptor) {
client.getOutInterceptors().add(interceptor);
client.getOutInterceptors().add(new LoggingOutInterceptor());
}
((HTTPConduit) client.getConduit()).setClient(httpClientPolicy);
return client;
}
public static BindingOperationInfo getBindingOperationInfo(Client client, String operation){
Endpoint endpoint = client.getEndpoint();
BindingInfo bindingInfo = endpoint.getEndpointInfo().getBinding();
QName opName = new QName(endpoint.getService().getName().getNamespaceURI(), operation);
BindingOperationInfo boi = bindingInfo.getOperation(opName);
if (boi == null) { // WebService 接口和实现类的 namespace 不相同的情况
for (BindingOperationInfo operationInfo : bindingInfo.getOperations()) {
if (operation.equals(operationInfo.getName().getLocalPart())) {
return operationInfo;
}
}
}
return boi;
}
public static Map<String, Class<?>> getInputParameters(BindingOperationInfo operationInfo) {
return getParameters(operationInfo, true);
}
public static Map<String, Class<?>> getOutputParameters(BindingOperationInfo operationInfo) {
return getParameters(operationInfo, false);
}
private static Map<String, Class<?>> getParameters(BindingOperationInfo boi, boolean input) {
BindingOperationInfo unWrappedBoi = boi.isUnwrapped() ? boi.getUnwrappedOperation() : boi.getWrappedOperation();
if(unWrappedBoi == null) { // 在服务端使用@SOAPBinding(style = SOAPBinding.Style.RPC),即设置绑定方式为RPC时,这个返回为空
unWrappedBoi = boi;
}
BindingMessageInfo bmi = (input ? unWrappedBoi.getInput() : unWrappedBoi.getOutput());
List<MessagePartInfo> messageParts = bmi.getMessageParts();
Map<String, Class<?>> result = new LinkedHashMap<String, Class<?>>(messageParts.size());
for (MessagePartInfo mpi : messageParts) {
result.put(mpi.getName().getLocalPart(), mpi.getTypeClass());
}
return result;
}
public static Object[] invokeWebService(String wsdlUrl, String operation, Object... parameters) {
return invokeWebService(wsdlUrl, operation, JaxWsDynamicClientFactory.class.getClassLoader(), parameters);
}
public static Object[] invokeWebService(String wsdlUrl, String operation,
ClassLoader classLoader, Object... parameters) {
// 动态创建 WebService 客户端
Client client = createJaxWsDynamicClient(wsdlUrl, classLoader);
// 调用 WebService 服务
return invokeWebService(client, operation, parameters);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Object[] invokeWebService(Client client, String operation, Object... parameters) {
Object[] invokeParameters = new Object[parameters.length];
try {
BindingOperationInfo boi = getBindingOperationInfo(client, operation);
if(boi == null)
throw new DefaultGboatNestedException(
"No operation was found with the name [" + operation + "] of namespace "
+ client.getEndpoint().getService().getName().getNamespaceURI());
BindingOperationInfo invokeBoi = null;
if(boi.isUnwrapped()) {
invokeBoi = boi.getUnwrappedOperation();
} else {
invokeBoi = boi.getWrappedOperation();
}
// 在服务端使用@SOAPBinding(style = SOAPBinding.Style.RPC),上边的方式拿到的invokeBoi是空的,因此做以下处理
if(null == invokeBoi) {
invokeBoi = boi;
}
// WebService 服务需要的输入参数的信息
Map<String,Class<?>> inputParamInfoMap = getInputParameters(boi);
if(ArrayUtils.isNotEmpty(parameters) && MapUtils.isNotEmpty(inputParamInfoMap)) {
List<Class<?>> needTypes = new ArrayList<Class<?>>(inputParamInfoMap.values());
Class<?> needType = null; // 需要的类型
Class<?> actualType = null; // 实际传入的类型
for (int i = 0, size = needTypes.size(); i < size; i++) {
// 如果实际传入的参数个数小于需要的参数个数,且实际传入的参数已经全部被处理完成,则中止循环
if(i >= parameters.length)
break;
// 如果当前参数值为 null,则什么也不做,直接跳过
if(parameters[i] == null) {
invokeParameters[i] = parameters[i];
continue;
}
// 如果传入参数值是java基本类型也不做处理,直接赋值
if(isNativeType(parameters[i].getClass())) {
invokeParameters[i] = parameters[i];
continue;
}
needType = needTypes.get(i);
actualType = parameters[i].getClass();
// 先进行参数类型校验
parametersValidate(parameters[i].getClass(), needType);
// 如果当前参数值可以强转为需要的参数类型或为原生类型,则什么也不做,直接跳过
if(needType == actualType || needType.isAssignableFrom(actualType) || ClassUtils.isPrimitiveOrWrapper(actualType)) {
continue;
}
// 使用需要的类型创建一个新的对象实例,并将当前参数的属性值复制给新创建的实例
Object obj = null;
try {
if (JAXBElement.class.isAssignableFrom(needType)
|| needType.isAnnotationPresent(XmlRootElement.class)
|| needType.isAnnotationPresent(XmlType.class)) { // 单个复杂对象处理
obj = JAXBUtil.castClone(parameters[i], needType);
} else if (Collection.class.isAssignableFrom(parameters[i].getClass())) { // List处理,如果根据needType判断,则即使服务端是List,needType的isArray也是true
// 取到原始的数组中的原子对象类型
Class<?> needComponentType = needType.getComponentType();
Collection collection = ArrayList.class.newInstance();
// 防止服务端传入的参数是实际的列表类,而不是接口
if(parameters[i] instanceof LinkedList) {
collection = LinkedList.class.newInstance();
}
List<?> listInputParameters = (List)parameters[i];
for(int j = 0; j < listInputParameters.size(); j++) {
Object tempDestObj = JAXBUtil.castClone(listInputParameters.get(j), needComponentType);
collection.add(tempDestObj);
}
obj = collection;
} else if(parameters[i].getClass().isArray() || needType.isArray()) { // 数组处理
// 数组类型的参数处理,判断数组时,不能用parameters[i]的方式,而应该全部获取到
Class<?> needComponentType = needType.getComponentType();
Object[] inArray = (Object[]) parameters[i];
// 即使服务端发布的服务参数是数组,也必须使用List对象传给参数,原因暂时没有搞清楚
Collection collection = ArrayList.class.newInstance();
// 防止服务端传入的参数是实际的列表类,而不是接口
if(parameters[i] instanceof LinkedList) {
collection = LinkedList.class.newInstance();
}
for(int j = 0; j < inArray.length; j++) {
Object tempDestObj = JAXBUtil.castClone(inArray[j], needComponentType);
collection.add(tempDestObj);
}
obj = collection;
} else {
obj = needType.newInstance();
BeanUtils.copyProperties(parameters[i], obj);
}
} catch (Exception e) {
logger.warn(
"通过 CXF 调用 WebService [{}] 时,将第 [{}] 个参数 [{}] 的属性值复制给目标类型的对象 [{}] 失败,将改用 JSON 转换的方式将其转换为目标类型。",
boi, i, actualType, needType);
logger.warn("异常信息:", e);
// 如果直接复制失败,则先将源对象转换成 Json 字符串,然后再将 Json 字符串转换成目标对象
String json = JsonUtil.object2Json(parameters[i]);
obj = JsonUtil.json2Object(json, needType);
}
invokeParameters[i] = obj;
}
}
// 调用 WebService 服务
return client.invoke(invokeBoi, invokeParameters);
} catch (Exception e) {
throw new DefaultGboatNestedException("使用 CXF 动态调用 WebService 服务 [" + operation + "] 失败", e);
}
}
private static void parametersValidate(Class<?> parameter, Class<?> destType) {
if(Map.class.isAssignableFrom(parameter)) {
throw new RuntimeException("暂时不支持Map类型,你可以将该类型作为一个类的成员变量这样的方式来完成调用。");
}
if(JAXBElement.class.isAssignableFrom(destType)) {
throw new RuntimeException("参数转换失败,请在webservice的服务端接口中标注@WebService注解!");
}
}
public static Object[] invokeWrappedWebService(String wsdlUrl, Object parameter){
return invokeWrappedWebService(wsdlUrl, parameter, JaxWsDynamicClientFactory.class.getClassLoader());
}
public static Object[] invokeWrappedWebService(String wsdlUrl, Object parameter, ClassLoader classLoader){
// 动态创建 WebService 客户端
Client client = createJaxWsDynamicClient(wsdlUrl, classLoader);
// 调用 WebService 服务
return invokeWrappedWebService(client, parameter);
}
public static Object[] invokeWrappedWebService(Client client, Object parameter) {
Assert.notNull(parameter, "使用经过 CXF 包装后客户端调用 WebService 失败,原因:传入的参数不能为 null");
Class<?> paramType = parameter.getClass();
XmlRootElement xmlRootElement = paramType.getAnnotation(XmlRootElement.class);
Assert.notNull(xmlRootElement, "使用经过 CXF 包装后客户端调用 WebService 失败,原因:传入的参数类型 [" + paramType + "] 必须有 javax.xml.bind.annotation.XmlRootElement 注解");
String operation = xmlRootElement.name();
if("##default".equals(operation)) {
operation = paramType.getSimpleName();
}
String reallyOperation = StringUtils.removeEnd(WordUtils.uncapitalize(operation), "Request");
try {
BindingOperationInfo boi = getBindingOperationInfo(client, reallyOperation);
if(boi == null)
throw new DefaultGboatNestedException(
"No operation was found with the name [" + reallyOperation + "] of namespace " + client.getEndpoint().getService().getName().getNamespaceURI());
QName qname = boi.getName();
String packageName = JAXBUtils.namespaceURIToPackage(qname.getNamespaceURI());
String simpleClassName = JAXBUtils.nameToIdentifier(operation, IdentifierType.CLASS);
String className = packageName + "." + simpleClassName;
// CXF 动态生成的客户端方法需要的参数类型
Class<?> needType = Thread.currentThread().getContextClassLoader().loadClass(className);
if(!needType.isAssignableFrom(paramType)){
// 将当前传入的参数转换成与需要的类型相匹配
parameter = JAXBUtil.castClone(parameter, needType);
}
// 调用 WebService 服务
return client.invoke(boi, parameter);
} catch (Exception e) {
throw new DefaultGboatNestedException("使用经过 CXF 包装后客户端调用 WebService [" + reallyOperation + "] 失败", e);
}
}
public static boolean isNativeType(Class<?> type) {
if (type.isPrimitive()) { // 基本类型
return true;
}
// 不可更改的变量类型 如 String,Long
if (type.equals(String.class))
return true;
if (type.equals(Long.class))
return true;
if(type.equals(Boolean.class))
return true;
if(type.equals(Short.class))
return true;
if(type.equals(Integer.class))
return true;
if(type.equals(Character.class))
return true;
if(type.equals(Float.class))
return true;
if(type.equals(Double.class))
return true;
if(type.equals(Byte.class))
return true;
return false;
}
}
jsonUtil代码
package ;
import ;
import .util.DateUtil;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.math.BigDecimal;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.fasterxml.jackson.databind.type.CollectionType;
import com.fasterxml.jackson.databind.type.MapLikeType;
import com.fasterxml.jackson.databind.type.TypeFactory;
@SuppressWarnings("unchecked")
public final class JsonUtil {
private static ObjectMapper MAPPER;
static {
MAPPER = generateMapper();
}
public static ObjectMapper generateMapper() {
return generateMapper(Include.ALWAYS);
}
public static ObjectMapper generateMapper(Include incl) {
return generateMapper(incl, DateUtil.DEFAULT_DATETIME_FORMAT);
}
public static ObjectMapper generateMapper(Include incl, String dateFormat) {
ObjectMapper objectMapper = initObjectMapper(incl, dateFormat);
SimpleModule module = new SimpleModule("GboatModule");
module.addSerializer(Enum.class, new GboatEnumSerializer())
.addSerializer(BigDecimal.class, new GboatBigDecimalSerializer())
.addDeserializer(Boolean.class, new GboatBooleanDeserializer())
.addDeserializer(Date.class, new GboatDateDeserializer());
objectMapper.registerModule(module);
return objectMapper;
}
public static ObjectMapper generateMapperDefaultEnum(Include incl, String dateFormat) {
ObjectMapper objectMapper = initObjectMapper(incl, dateFormat);
SimpleModule module = new SimpleModule("GboatModule");
module.addSerializer(BigDecimal.class, new GboatBigDecimalSerializer())
.addDeserializer(Boolean.class, new GboatBooleanDeserializer())
.addDeserializer(Date.class, new GboatDateDeserializer());
objectMapper.registerModule(module);
return objectMapper;
}
private static ObjectMapper initObjectMapper(Include incl, String dateFormat) {
ObjectMapper objectMapper = new ObjectMapper();
// 设置输入时忽略在 JSON 字符串中存在但 Java 对象实际没有的属性
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 对于原生数据类型的属性允许 JSON 字符串中的值为 null
objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);
// 禁止使用 int 代表 Enum 的 order() 来反序列化 Enum,非常危险
objectMapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, true);
//允许数组为单值
objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
objectMapper.configure(SerializationFeature.INDENT_OUTPUT, false);
objectMapper.configure(SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN, true);
// 设置输出时包含属性的风格
objectMapper.setSerializationInclusion(incl);
// 设置默认日期格式
objectMapper.setDateFormat(new SimpleDateFormat(dateFormat));
// objectMapper.setFilters(new SimpleFilterProvider().setFailOnUnknownId(false));
return objectMapper;
}
public static <T> T json2Object(String json, Class<T> clazz) {
if (String.class.equals(clazz)) {
return (T) json;
}
try {
return (T) MAPPER.readValue(json, clazz);
} catch (Exception e) {
throw new DefaultGboatNestedException("将 " + json + " 转换成 " + clazz + " 对象失败。", e);
}
}
public static <T> T json2Object(String json, TypeReference<T> typeReference) {
if (String.class.equals(typeReference.getType())) {
return (T) json;
}
try {
return (T) MAPPER.readValue(json, typeReference);
} catch (Exception e) {
throw new DefaultGboatNestedException("将 " + json + " 转换成 " + typeReference.getType() + " 对象失败。", e);
}
}
public static <T> List<T> json2List(String json, Class<T> elementClass) {
CollectionType typeReference = TypeFactory.defaultInstance()
.constructCollectionType(ArrayList.class, elementClass);
try {
return (List<T>) MAPPER.readValue(json, typeReference);
} catch (Exception e) {
throw new DefaultGboatNestedException("将 " + json + " 转换成 List<" + elementClass + "> 对象失败。", e);
}
}
public static <K, V> Map<K, V> json2Map(String json, Class<K> keyClass,
Class<V> valueClass) {
MapLikeType typeReference = TypeFactory
.defaultInstance()
.constructMapLikeType(LinkedHashMap.class, keyClass, valueClass);
try {
return (Map<K, V>) MAPPER.readValue(json, typeReference);
} catch (Exception e) {
throw new DefaultGboatNestedException("将 " + json + " 转换成 Map<" + keyClass + ", " + valueClass + "> 对象失败。", e);
}
}
public static String object2Json(Object obj) {
try {
return MAPPER.writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new DefaultGboatNestedException("将 " + obj + " 转换成 JSON 字符串失败。", e);
}
}
public static String object2Json(Object obj, String[] properties) {
try {
return getIncludeObjectWriter(obj.getClass(), properties).writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new DefaultGboatNestedException("将 " + obj + " 转换成 JSON 字符串失败。", e);
}
}
public static String object2JsonWithExcludeProps(Object obj, String[] excludeProperties) {
try {
return getExcludeObjectWriter(obj.getClass(), excludeProperties).writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new DefaultGboatNestedException("将 " + obj + " 转换成 JSON 字符串失败。", e);
}
}
public static void object2Json(OutputStream out, Object obj) {
try {
MAPPER.writeValue(out, obj);
} catch (Exception e) {
throw new DefaultGboatNestedException(e);
}
}
public static void object2Json(OutputStream out, Object obj, String[] properties) {
try {
getIncludeObjectWriter(obj.getClass(), properties).writeValue(out, obj);
} catch (Exception e) {
throw new DefaultGboatNestedException(e);
}
}
public static void object2JsonWithExcludeProps(OutputStream out, Object obj, String[] excludeProperties) {
try {
getExcludeObjectWriter(obj.getClass(), excludeProperties).writeValue(out, obj);
} catch (Exception e) {
throw new DefaultGboatNestedException(e);
}
}
public static void object2Json(Writer write, Object obj) {
try {
MAPPER.writeValue(write, obj);
} catch (Exception e) {
throw new DefaultGboatNestedException(e);
}
}
public static void object2Json(Writer write, Object obj, String[] properties) {
try {
getIncludeObjectWriter(obj.getClass(), properties).writeValue(write, obj);
} catch (Exception e) {
throw new DefaultGboatNestedException(e);
}
}
public static void object2JsonWithExcludeProps(Writer write, Object obj, String[] excludeProperties) {
try {
getExcludeObjectWriter(obj.getClass(), excludeProperties).writeValue(write, obj);
} catch (Exception e) {
throw new DefaultGboatNestedException(e);
}
}
public static void object2Json(File file, Object obj) {
try {
MAPPER.writeValue(file, obj);
} catch (Exception e) {
throw new DefaultGboatNestedException(e);
}
}
public static void object2Json(File file, Object obj, String[] properties) {
try {
getIncludeObjectWriter(obj.getClass(), properties).writeValue(file, obj);
} catch (Exception e) {
throw new DefaultGboatNestedException(e);
}
}
public static void object2JsonWithExcludeProps(File file, Object obj, String[] excludeProperties) {
try {
getExcludeObjectWriter(obj.getClass(), excludeProperties).writeValue(file, obj);
} catch (Exception e) {
throw new DefaultGboatNestedException(e);
}
}
public static JsonNode fromString(String json) {
return fromString(json, null);
}
public static JsonNode fromString(String json, String defaultValue) {
try {
JsonNode result = MAPPER.readTree(json);
if (StringUtils.isNotBlank(defaultValue) && (result instanceof ObjectNode)) {
extend((ObjectNode) result, MAPPER.readTree(defaultValue));
}
return result;
} catch (IOException e) {
throw new DefaultGboatNestedException("解析 JSON 字符串失败", e);
}
}
public static JsonNode fromResource(String resource) {
return fromResource(resource, null);
}
public static JsonNode fromResource(String resource, ClassLoader classLoader) {
if (classLoader == null) {
classLoader = Thread.currentThread().getContextClassLoader();
}
final URL url = classLoader.getResource(resource);
if (url == null) {
throw new DefaultGboatNestedException("resource " + resource + " not found");
}
return fromURL(url);
}
public static JsonNode fromURL(URL url) {
try {
return MAPPER.readTree(url);
} catch (IOException e) {
throw new DefaultGboatNestedException("将 URL [" + url + "] 的内容转换为 JsonNode 失败。", e);
}
}
public static JsonNode fromPath(String path) {
return fromFile(new File(path));
}
public static JsonNode fromFile(File file) {
try {
return MAPPER.readTree(file);
} catch (IOException e) {
throw new DefaultGboatNestedException("将文件 [" + file + "] 的内容转换为 JsonNode 失败。", e);
}
}
public static JsonNode fromReader(final Reader reader) {
try {
return MAPPER.readTree(reader);
} catch (Exception e) {
throw new DefaultGboatNestedException("从 Reader 加载 JSON 数据发生错误。", e);
}
}
public static JsonNode fromInputStream(InputStream in) {
try {
return MAPPER.readTree(in);
} catch (Exception e) {
throw new DefaultGboatNestedException("从输入流加载 JSON 数据发生错误。", e);
}
}
private static ObjectWriter getIncludeObjectWriter(Class<?> clazz, String[] properties) {
return getObjectWriter(clazz, properties, true);
}
private static ObjectWriter getExcludeObjectWriter(Class<?> clazz, String[] excludeProperties) {
return getObjectWriter(clazz, excludeProperties, true);
}
private static ObjectWriter getObjectWriter(Class<?> clazz, String[] properties, boolean exclude) {
// 如果是需要排除指定属性,且需要排除的属性列表为空,则直接返回默认的 ObjectWriter
if (exclude && ArrayUtils.isEmpty(properties)) {
return MAPPER.writer();
}
JsonFilter jsonFilter = clazz.getAnnotation(JsonFilter.class);
if (jsonFilter == null) {
throw new IllegalArgumentException(clazz + " 的类定义没有使用 @JsonFilter 注解进行标注时");
}
String filterId = jsonFilter.value();
SimpleBeanPropertyFilter filter = exclude ? SimpleBeanPropertyFilter.serializeAllExcept(properties)
: SimpleBeanPropertyFilter.filterOutAllExcept(properties);
return MAPPER.writer(new SimpleFilterProvider().addFilter(filterId, filter));
}
public static void extend(ObjectNode obj, JsonNode def){
Iterator<Entry<String, JsonNode>> defaultFields = def.fields();
Entry<String, JsonNode> entry = null;
while (defaultFields.hasNext()) {
entry = defaultFields.next();
String key = entry.getKey();
JsonNode defVal = entry.getValue();
if (defVal == null || defVal.getNodeType() == JsonNodeType.NULL) {
continue;
}
JsonNode value = obj.get(key);
if (value == null || value.getNodeType() == JsonNodeType.NULL) {
obj.put(key, defVal);
} else if (value instanceof ObjectNode) {
extend((ObjectNode)value, defVal);
}
}
}
}
JAXBUtil工具类代码
package gboat2.base.bridge.util.xml;
import gboat2.base.bridge.GboatAppConstants;
import gboat2.base.bridge.exception.DefaultGboatNestedException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URL;
import java.util.Arrays;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.JAXBIntrospector;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.UnmarshallerHandler;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.util.JAXBSource;
import javax.xml.namespace.QName;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.WordUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLFilter;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLFilterImpl;
import com.thoughtworks.xstream.XStream;
public class JAXBUtil {
public static Marshaller createMarshaller(Class<?>... classesToBeBound){
if(ArrayUtils.isEmpty(classesToBeBound)) {
throw new IllegalArgumentException("传入的 class 为空");
}
try {
JAXBContext jaxbContext = JAXBContext.newInstance(classesToBeBound);
Marshaller marshaller = jaxbContext.createMarshaller();
setMarshallerProperty(marshaller);
return marshaller;
} catch (JAXBException e) {
throw new DefaultGboatNestedException("创建 JAXB 编组对象失败。classesToBeBound=" + Arrays.toString(classesToBeBound), e);
}
}
public static Marshaller createMarshaller(String contextPath){
return createMarshaller(contextPath, Thread.currentThread().getContextClassLoader());
}
public static Marshaller createMarshaller(String contextPath , ClassLoader classLoader){
try {
JAXBContext jaxbContext = JAXBContext.newInstance(contextPath, classLoader);
Marshaller marshaller = jaxbContext.createMarshaller();
setMarshallerProperty(marshaller);
return marshaller;
} catch (JAXBException e) {
throw new DefaultGboatNestedException("创建 JAXB 编组对象失败。contextPath=" + contextPath, e);
}
}
private static void setMarshallerProperty(Marshaller marshaller) throws PropertyException{
marshaller.setProperty("com.sun.xml.bind.xmlDeclaration", Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.setProperty("com.sun.xml.bind.characterEscapeHandler", new XmlCharacterEscapeHandler() );
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new NamespacePrefixMapperImpl());
}
public static Unmarshaller createUnmarshaller(Class<?>... classesToBeBound){
if(ArrayUtils.isEmpty(classesToBeBound)) {
throw new IllegalArgumentException("传入的 class 为空");
}
try {
JAXBContext jaxbContext = JAXBContext.newInstance(classesToBeBound);
return jaxbContext.createUnmarshaller();
} catch (JAXBException e) {
throw new DefaultGboatNestedException("创建 JAXB 解组对象失败。classesToBeBound=" + Arrays.toString(classesToBeBound), e);
}
}
public static Unmarshaller createUnmarshaller(String contextPath){
return createUnmarshaller(contextPath, Thread.currentThread().getContextClassLoader());
}
public static Unmarshaller createUnmarshaller(String contextPath , ClassLoader classLoader){
try {
JAXBContext jaxbContext = JAXBContext.newInstance(contextPath, classLoader);
return jaxbContext.createUnmarshaller();
} catch (JAXBException e) {
throw new DefaultGboatNestedException("创建 JAXB 解组对象失败。contextPath=" + contextPath, e);
}
}
public static String object2xml(Object obj) {
StringWriter writer = new StringWriter();
try {
object2xml(obj, writer);
return writer.toString();
} finally {
IOUtils.closeQuietly(writer);
}
}
public static void object2xml(Object obj, Writer writer) {
try {
createMarshaller(obj.getClass()).marshal(wrapWithJAXB(obj), writer);
} catch (JAXBException e) {
throw new DefaultGboatNestedException("将 JAXB Element 转为 XML 失败。", e);
}
}
public static String object2xmlByXStream(Object source, Class<?> dest) {
XStream xstream = new XStream();
xstream.alias(dest.getName(), source.getClass());
return xstream.toXML(source);
}
public static void object2xml(Object obj, String xmlFilePath){
object2xml(obj, new File(xmlFilePath));
}
public static void object2xml(Object obj, File xmlFile){
try {
createMarshaller(obj.getClass()).marshal(wrapWithJAXB(obj), xmlFile);
} catch (JAXBException e) {
throw new DefaultGboatNestedException("将 JAXB Element 转为 XML 失败。", e);
}
}
public static void object2xml(Object obj, OutputStream out){
try {
createMarshaller(obj.getClass()).marshal(wrapWithJAXB(obj), out);
} catch (JAXBException e) {
throw new DefaultGboatNestedException("将 JAXB Element 转为 XML 失败。", e);
}
}
public static <T> T xml2object(String xml, Class<T> beanClass) {
if (StringUtils.isBlank(xml)) {
return null;
}
Reader reader = new StringReader(xml);
try {
return (T) xml2object(reader, beanClass);
} finally {
IOUtils.closeQuietly(reader);
}
}
@SuppressWarnings("unchecked")
public static <T> T xml2objectIgnoreNameSpace(Unmarshaller unmarshaller,Reader reader, Class<T> beanClass) throws ParserConfigurationException, SAXException, IOException, IllegalStateException, JAXBException{
Object result = null;
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
SAXParser saxParser = saxFactory.newSAXParser();
XMLReader xmlReader = saxParser.getXMLReader();
XMLFilter xmlFilter = new IgnoreNameSpaceXMLFilter(xmlReader);
UnmarshallerHandler unmarshallerHandler = unmarshaller.getUnmarshallerHandler();
xmlFilter.setContentHandler(unmarshallerHandler);
xmlFilter.parse(new InputSource(reader));
result = unmarshallerHandler.getResult();
if (JAXBElement.class.equals(result.getClass())
&& !JAXBElement.class.equals(beanClass)
&& beanClass.isAssignableFrom(((JAXBElement<?>) result).getDeclaredType())) {
return (T) JAXBIntrospector.getValue(result);
}
return (T) result;
}
@SuppressWarnings("unchecked")
public static <T> T xml2object(Reader reader, Class<T> beanClass){
Object result = null;
try {
Unmarshaller unmarshaller = createUnmarshaller(beanClass);
result = unmarshaller.unmarshal(reader);
} catch (JAXBException e) {
throw new DefaultGboatNestedException("将 XML 转为 Java 对象失败,beanClass=" + beanClass, e);
}
if (JAXBElement.class.equals(result.getClass())
&& !JAXBElement.class.equals(beanClass)
&& beanClass.isAssignableFrom(((JAXBElement<?>) result).getDeclaredType())) {
return (T) JAXBIntrospector.getValue(result);
}
return (T) result;
}
@SuppressWarnings("unchecked")
public static <T> T xml2object(File xmlFile, Class<T> beanClass){
Object result = null;
try {
result = createUnmarshaller(beanClass).unmarshal(xmlFile);
} catch (JAXBException e) {
throw new DefaultGboatNestedException("将 XML 转为 Java 对象失败,beanClass=" + beanClass + ", xmlFile=" + xmlFile, e);
}
if (JAXBElement.class.equals(result.getClass())
&& !JAXBElement.class.equals(beanClass)
&& beanClass.isAssignableFrom(((JAXBElement<?>) result).getDeclaredType())) {
return (T) JAXBIntrospector.getValue(result);
}
return (T) result;
}
@SuppressWarnings("unchecked")
public static <T> T xml2object(URL url, Class<T> beanClass){
Object result = null;
try {
result = createUnmarshaller(beanClass).unmarshal(url);
} catch (JAXBException e) {
throw new DefaultGboatNestedException("将 XML 转为 Java 对象失败,beanClass=" + beanClass + ", url=" + url, e);
}
if (JAXBElement.class.equals(result.getClass())
&& !JAXBElement.class.equals(beanClass)
&& beanClass.isAssignableFrom(((JAXBElement<?>) result).getDeclaredType())) {
return (T) JAXBIntrospector.getValue(result);
}
return (T) result;
}
@SuppressWarnings("unchecked")
public static <T> T xml2object(InputStream input, Class<T> beanClass){
Object result = null;
try {
result = createUnmarshaller(beanClass).unmarshal(input);
} catch (JAXBException e) {
throw new DefaultGboatNestedException("将 XML 转为 Java 对象失败,beanClass=" + beanClass, e);
}
if (JAXBElement.class.equals(result.getClass())
&& !JAXBElement.class.equals(beanClass)
&& beanClass.isAssignableFrom(((JAXBElement<?>) result).getDeclaredType())) {
return (T) JAXBIntrospector.getValue(result);
}
return (T) result;
}
@SuppressWarnings("unchecked")
public static <T> T deepCopyJAXB(T jaxbObj) {
if (jaxbObj == null) {
return null;
}
try {
JAXBContext jaxbContext = JAXBContext.newInstance(jaxbObj.getClass());
Object wrappedObj = wrapWithJAXB(jaxbObj);
JAXBSource source = new JAXBSource(jaxbContext, wrappedObj);
Object result = jaxbContext.createUnmarshaller().unmarshal(source);
return wrappedObj.equals(jaxbObj) ? (T) result : (T) JAXBIntrospector.getValue(result);
} catch (JAXBException e) {
throw new DefaultGboatNestedException("深度复制 JAXB Element 失败。", e);
}
}
@SuppressWarnings("unchecked")
private static <T> Object wrapWithJAXB(T obj){
if(obj == null) {
return null;
}
if(obj instanceof JAXBElement) {
return obj;
}
Class<T> clazz = (Class<T>) obj.getClass();
if(clazz.getAnnotation(XmlRootElement.class) != null) {
return obj;
}
String namespaceURI = getNameSpace(clazz);
String localPart = getLocalPart(clazz);
return new JAXBElement<T>(new QName(namespaceURI, localPart), clazz, obj);
}
private static String getLocalPart(Class<?> clazz) {
String localPart = null;
// 源对象的 @XmlType 注解
XmlType sourceXmlType = clazz.getAnnotation(XmlType.class);
if (sourceXmlType != null) {
localPart = sourceXmlType.name();
}
if (localPart == null || "##default".equals(localPart)) {
localPart = WordUtils.uncapitalize(clazz.getSimpleName());
}
return localPart;
}
private static String getNameSpace(Class<?> clazz) {
String namespaceURI = null;
// 源对象的 @XmlType 注解
XmlType sourceXmlType = clazz.getAnnotation(XmlType.class);
if (sourceXmlType != null) {
namespaceURI = sourceXmlType.namespace();
}
// 如果源对象的 @XmlType 注解没有明确指定 namespace 或 name
if (namespaceURI == null || "##default".equals(namespaceURI)) {
namespaceURI = XMLConstants.NULL_NS_URI;
}
return namespaceURI;
}
public static <T> T castClone(Object source, Class<T> destType) {
return (T)castClone(source, destType, null);
}
public static <T> T castClone(Object source, Class<T> destType,ClassLoader destClassLoader) {
return (T)castClone(source, destType, false,destClassLoader);
}
public static <T> T castClone(Object source, Class<T> destType,boolean ignoreNameSpace) {
return (T)castClone(source, destType, ignoreNameSpace,null);
}
@SuppressWarnings({ "unchecked"})
public static <T> T castClone(Object source, Class<T> destType,boolean ignoreNameSpace, ClassLoader destClassLoader) {
if(source == null) {
return null;
}
Object result = null;
String xml = object2xml(source);
xml = xml.replaceAll("[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]", "");
Unmarshaller unmarshaller = (destClassLoader == null) ? createUnmarshaller(destType) : createUnmarshaller(destType.getPackage().getName(), destClassLoader);
StringReader reader = null;
reader = new StringReader(xml);
if(ignoreNameSpace){
try {
result = xml2objectIgnoreNameSpace(unmarshaller,reader,destType);
} catch (IllegalStateException e) {
throw new DefaultGboatNestedException("通过 JAXB 将 XML 转换成 JavaBean 失败,destType=" + destType + ", xml=\n" + xml, e);
} catch (ParserConfigurationException e) {
throw new DefaultGboatNestedException("通过 JAXB 将 XML 转换成 JavaBean 失败,destType=" + destType + ", xml=\n" + xml, e);
} catch (SAXException e) {
throw new DefaultGboatNestedException("通过 JAXB 将 XML 转换成 JavaBean 失败,destType=" + destType + ", xml=\n" + xml, e);
} catch (IOException e) {
throw new DefaultGboatNestedException("通过 JAXB 将 XML 转换成 JavaBean 失败,destType=" + destType + ", xml=\n" + xml, e);
} catch (JAXBException e) {
throw new DefaultGboatNestedException("通过 JAXB 将 XML 转换成 JavaBean 失败,destType=" + destType + ", xml=\n" + xml, e);
}
}else{
try {
XMLInputFactory xmlFactory = XMLInputFactory.newInstance();
XMLStreamReader reader2 = xmlFactory.createXMLStreamReader(reader);
// 采用这种方式则不需要java对象类必须使用@XmlRootElement注解的问题
JAXBElement userElement = unmarshaller.unmarshal(reader2, destType);
result = userElement.getValue();
} catch (Exception e) {
throw new DefaultGboatNestedException("通过 JAXB 将 XML 转换成 JavaBean 失败,destType=" + destType + ", xml=\n" + xml, e);
} finally {
IOUtils.closeQuietly(reader);
}
}
return (T)result;
}
private static class IgnoreNameSpaceXMLFilter extends XMLFilterImpl {
public IgnoreNameSpaceXMLFilter(XMLReader xmlReader) {
super(xmlReader);
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
int colonIndex = qName.indexOf(':');
if(colonIndex >= 0) {
qName = qName.substring(colonIndex + 1);
}
super.startElement(uri, localName, qName, attributes);
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
int colonIndex = qName.indexOf(':');
if(colonIndex >= 0) {
qName = qName.substring(colonIndex + 1);
}
super.endElement(uri, localName, qName);
}
}
}