java分布式环境下,反序列化遇到类型擦除问题,解决思路
2017-04-27 20:41
567 查看
前言
公司使用springcloud搭建了一个分布式框架。但是在框架之间调用的时候,如果返回结果的真实类型涉及到泛型,就会遇到类型擦除的问题。这个问题的解决方案是,框架中数据传输时候序列化和反序列化的时候,需要获取数据的真实类型,来进行反序列化。序列化的方案
1. 使用java的IO进行序列化和反序列化2.使用json来进行序列化和反序列化
3.使用hessian来进行序列化和反序列化
4.使用dubbo协议来进行序列化和反序列化
虽然有很多序列化和反序列化方案,但是想要写出能够解决泛型擦除问题的代码还是非常困难的。
代码
翻阅大量资料之后,终于在dubbo框架的dubbo-common源码中找到了具体实现。代码可以参考dubbo-common包,该jar包是阿里的dubbo框架的common,里面有上述所有方案的具体实现。
这里仅仅展示FastJson的实现
FastJsonSerialization.java
/* * Copyright 1999-2011 Alibaba Group. * * 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.alibaba.dubbo.common.serialize.support.json; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import com.alibaba.dubbo.common.URL; import com.alibaba.dubbo.common.serialize.ObjectInput; import com.alibaba.dubbo.common.serialize.ObjectOutput; import com.alibaba.dubbo.common.serialize.Serialization; /** * FastJsonSerialization * * @author william.liangf */ public class FastJsonSerialization implements Serialization { public byte getContentTypeId() { return 6; } public String getContentType() { return "text/json"; } public ObjectOutput serialize(URL url, OutputStream output) throws IOException { return new FastJsonObjectOutput(output); } public ObjectInput deserialize(URL url, InputStream input) throws IOException { return new FastJsonObjectInput(input); } }
FastJsonObjectOutput.java
/* * Copyright 1999-2011 Alibaba Group. * * 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.alibaba.dubbo.common.serialize.support.json; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.Writer; import com.alibaba.dubbo.common.serialize.ObjectOutput; import com.alibaba.fastjson.serializer.JSONSerializer; import com.alibaba.fastjson.serializer.SerializeWriter; import com.alibaba.fastjson.serializer.SerializerFeature; /** * JsonObjectOutput * * @author william.liangf */ public class FastJsonObjectOutput implements ObjectOutput { private final PrintWriter writer; public FastJsonObjectOutput(OutputStream out) { this(new OutputStreamWriter(out)); } public FastJsonObjectOutput(Writer writer) { this.writer = new PrintWriter(writer); } public void writeBool(boolean v) throws IOException { writeObject(v); } public void writeByte(byte v) throws IOException { writeObject(v); } public void writeShort(short v) throws IOException { writeObject(v); } public void writeInt(int v) throws IOException { writeObject(v); } public void writeLong(long v) throws IOExc 19cad eption { writeObject(v); } public void writeFloat(float v) throws IOException { writeObject(v); } public void writeDouble(double v) throws IOException { writeObject(v); } public void writeUTF(String v) throws IOException { writeObject(v); } public void writeBytes(byte[] b) throws IOException { writer.println(new String(b)); } public void writeBytes(byte[] b, int off, int len) throws IOException { writer.println(new String(b, off, len)); } public void writeObject(Object obj) throws IOException { SerializeWriter out = new SerializeWriter(); JSONSerializer serializer = new JSONSerializer(out); serializer.config(SerializerFeature.WriteEnumUsingToString, true); serializer.write(obj); out.writeTo(writer); writer.println(); writer.flush(); } public void flushBuffer() throws IOException { writer.flush(); } }FastJsonObjectInput.java
/* * Copyright 1999-2011 Alibaba Group. * * 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.alibaba.dubbo.common.serialize.support.json; import java.io.BufferedReader; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.lang.reflect.Type; import com.alibaba.dubbo.common.serialize.ObjectInput; import com.alibaba.dubbo.common.utils.PojoUtils; import com.alibaba.fastjson.JSON; /** * JsonObjectInput * * @author william.liangf */ public class FastJsonObjectInput implements ObjectInput { private final BufferedReader reader; public FastJsonObjectInput(InputStream in){ this(new InputStreamReader(in)); } public FastJsonObjectInput(Reader reader){ this.reader = new BufferedReader(reader); } public boolean readBool() throws IOException { try { return readObject(boolean.class); } catch (ClassNotFoundException e) { throw new IOException(e.getMessage()); } } public byte readByte() throws IOException { try { return readObject( byte.class); } catch (ClassNotFoundException e) { throw new IOException(e.getMessage()); } } public short readShort() throws IOException { try { return readObject(short.class); } catch (ClassNotFoundException e) { throw new IOException(e.getMessage()); } } public int readInt() throws IOException { try { return readObject(int.class); } catch (ClassNotFoundException e) { throw new IOException(e.getMessage()); } } public long readLong() throws IOException { try { return readObject(long.class); } catch (ClassNotFoundException e) { throw new IOException(e.getMessage()); } } public float readFloat() throws IOException { try { return readObject(float.class); } catch (ClassNotFoundException e) { throw new IOException(e.getMessage()); } } public double readDouble() throws IOException { try { return readObject(double.class); } catch (ClassNotFoundException e) { throw new IOException(e.getMessage()); } } public String readUTF() throws IOException { try { return readObject(String.class); } catch (ClassNotFoundException e) { throw new IOException(e.getMessage()); } } public byte[] readBytes() throws IOException { return readLine().getBytes(); } public Object readObject() throws IOException, ClassNotFoundException { String json = readLine(); return JSON.parse(json); } public <T> T readObject(Class<T> cls) throws IOException, ClassNotFoundException { String json = readLine(); return JSON.parseObject(json, cls); } @SuppressWarnings("unchecked") public <T> T readObject(Class<T> cls, Type type) throws IOException,ClassNotFoundException { Object value = readObject(cls); return (T) PojoUtils.realize(value, cls, type); } private String readLine() throws IOException, EOFException { String line = reader.readLine(); if(line == null || line.trim().length() == 0) throw new EOFException(); return line; } }PojoUtils.java
/* * Copyright 1999-2011 Alibaba Group. * * 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.alibaba.dubbo.common.utils; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Proxy; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.IdentityHashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.TreeMap; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentSkipListMap; /** * PojoUtils. Travel object deeply, and convert complex type to simple type. * <p> * Simple type below will be remained: * <ul> * <li> Primitive Type, also include <b>String</b>, <b>Number</b>(Integer, Long), <b>Date</b> * <li> Array of Primitive Type * <li> Collection, eg: List, Map, Set etc. * </ul> * <p> * Other type will be covert to a map which contains the attributes and value pair of object. * * @author william.liangf * @author ding.lid */ public class PojoUtils { private static final ConcurrentMap<String, Method> NAME_METHODS_CACHE = new ConcurrentHashMap<String, Method>(); private static final ConcurrentMap<Class<?>, ConcurrentMap<String, Field>> CLASS_FIELD_CACHE = new ConcurrentHashMap<Class<?>, ConcurrentMap<String, Field>>(); public static Object[] generalize(Object[] objs) { Object[] dests = new Object[objs.length]; for (int i = 0; i < objs.length; i ++) { dests[i] = generalize(objs[i]); } return dests; } public static Object[] realize(Object[] objs, Class<?>[] types) { if (objs.length != types.length) throw new IllegalArgumentException("args.length != types.length"); Object[] dests = new Object[objs.length]; for (int i = 0; i < objs.length; i ++) { dests[i] = realize(objs[i], types[i]); } return dests; } public static Object[] realize(Object[] objs, Class<?>[] types, Type[] gtypes) { if (objs.length != types.length || objs.length != gtypes.length) throw new IllegalArgumentException("args.length != types.length"); Object[] dests = new Object[objs.length]; for (int i = 0; i < objs.length; i ++) { dests[i] = realize(objs[i], types[i], gtypes[i]); } return dests; } public static Object generalize(Object pojo) { return generalize(pojo, new IdentityHashMap<Object, Object>()); } @SuppressWarnings("unchecked") private static Object generalize(Object pojo, Map<Object, Object> history) { if (pojo == null) { return null; } if (pojo instanceof Enum<?>) { return ((Enum<?>)pojo).name(); } if (pojo.getClass().isArray() && Enum.class.isAssignableFrom( pojo.getClass().getComponentType())) { int len = Array.getLength(pojo); String[] values = new String[len]; for (int i = 0; i < len; i ++) { values[i] = ((Enum<?>)Array.get(pojo, i)).name(); } return values; } if (ReflectUtils.isPrimitives(pojo.getClass())) { return pojo; } if (pojo instanceof Class) { return ((Class)pojo).getName(); } Object o = history.get(pojo); if(o != null){ return o; } history.put(pojo, pojo); if (pojo.getClass().isArray()) { int len = Array.getLength(pojo); Object[] dest = new Object[len]; history.put(pojo, dest); for (int i = 0; i < len; i ++) { Object obj = Array.get(pojo, i); dest[i] = generalize(obj, history); } return dest; } if (pojo instanceof Collection<?>) { Collection<Object> src = (Collection<Object>)pojo; int len = src.size(); Collection<Object> dest = (pojo instanceof List<?>) ? new ArrayList<Object>(len) : new HashSet<Object>(len); history.put(pojo, dest); for (Object obj : src) { dest.add(generalize(obj, history)); } return dest; } if (pojo instanceof Map<?, ?>) { Map<Object, Object> src = (Map<Object, Object>)pojo; Map<Object, Object> dest= createMap(src); history.put(pojo, dest); for (Map.Entry<Object, Object> obj : src.entrySet()) { dest.put(generalize(obj.getKey(), history), generalize(obj.getValue(), history)); } return dest; } Map<String, Object> map = new HashMap<String, Object>(); history.put(pojo, map); map.put("class", pojo.getClass().getName()); for (Method method : pojo.getClass().getMethods()) { if (ReflectUtils.isBeanPropertyReadMethod(method)) { try { map.put(ReflectUtils.getPropertyNameFromBeanReadMethod(method), generalize(method.invoke(pojo), history)); } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } } } // public field for(Field field : pojo.getClass().getFields()) { if (ReflectUtils.isPublicInstanceField(field)) { try { Object fieldValue = field.get(pojo); // public filed同时也有get/set方法,如果get/set存取的不是前面那个 public field 该如何处理 if (history.containsKey(pojo)) { Object pojoGenerilizedValue = history.get(pojo); if (pojoGenerilizedValue instanceof Map && ((Map)pojoGenerilizedValue).containsKey(field.getName())) { continue; } } if (fieldValue != null) { map.put(field.getName(), generalize(fieldValue, history)); } } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } } } return map; } public static Object realize(Object pojo, Class<?> type) { return realize0(pojo, type, null , new IdentityHashMap<Object, Object>()); } public static Object realize(Object pojo, Class<?> type, Type genericType) { return realize0(pojo, type, genericType, new IdentityHashMap<Object, Object>()); } private static class PojoInvocationHandler implements InvocationHandler { private Map<Object, Object> map; public PojoInvocationHandler(Map<Object, Object> map) { this.map = map; } @SuppressWarnings("unchecked") public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getDeclaringClass() == Object.class) { return method.invoke(map, args); } String methodName = method.getName(); Object value = null; if (methodName.length() > 3 && methodName.startsWith("get")) { value = map.get(methodName.substring(3, 4).toLowerCase() + methodName.substring(4)); } else if (methodName.length() > 2 && methodName.startsWith("is")) { value = map.get(methodName.substring(2, 3).toLowerCase() + methodName.substring(3)); } else { value = map.get(methodName.substring(0, 1).toLowerCase() + methodName.substring(1)); } if (value instanceof Map<?,?> && ! Map.class.isAssignableFrom(method.getReturnType())) { value = realize0((Map<String, Object>) value, method.getReturnType(), null, new IdentityHashMap<Object, Object>()); } return value; } } @SuppressWarnings("unchecked") private static Collection<Object> createCollection(Class<?> type, int len) { if (type.isAssignableFrom(ArrayList.class)) { return new ArrayList<Object>(len); } if (type.isAssignableFrom(HashSet.class)) { return new HashSet<Object>(len); } if (! type.isInterface() && ! Modifier.isAbstract(type.getModifiers())) { try { return (Collection<Object>) type.newInstance(); } catch (Exception e) { // ignore } } return new ArrayList<Object>(); } private static Map createMap(Map src) { Class<? extends Map> cl = src.getClass(); Map result = null; if (HashMap.class == cl) { result = new HashMap(); } else if (Hashtable.class == cl) { result = new Hashtable(); } else if (IdentityHashMap.class == cl) { result = new IdentityHashMap(); } else if (LinkedHashMap.class == cl) { result = new LinkedHashMap(); } else if (Properties.class == cl) { result = new Properties(); } else if (TreeMap.class == cl) { result = new TreeMap(); } else if (WeakHashMap.class == cl) { return new WeakHashMap(); } else if (ConcurrentHashMap.class == cl) { result = new ConcurrentHashMap(); } else if (ConcurrentSkipListMap.class == cl) { result = new ConcurrentSkipListMap(); } else { try { result = cl.newInstance(); } catch (Exception e) { /* ignore */ } if (result == null) { try { Constructor<?> constructor = cl.getConstructor(Map.class); result = (Map)constructor.newInstance(Collections.EMPTY_MAP); } catch (Exception e) { /* ignore */ } } } if (result == null) { result = new HashMap<Object, Object>(); } return result; } @SuppressWarnings({ "unchecked", "rawtypes" }) private static Object realize0(Object pojo, Class<?> type, Type genericType, final Map<Object, Object> history) { if (pojo == null) { return null; } if (type != null && type.isEnum() && pojo.getClass() == String.class) { return Enum.valueOf((Class<Enum>)type, (String)pojo); } if (ReflectUtils.isPrimitives(pojo.getClass()) && ! (type != null && type.isArray() && type.getComponentType().isEnum() && pojo.getClass() == String[].class)) { return CompatibleTypeUtils.compatibleTypeConvert(pojo, type); } Object o = history.get(pojo); if(o != null){ return o; } history.put(pojo, pojo); if (pojo.getClass().isArray()) { if (Collection.class.isAssignableFrom(type)) { Class<?> ctype = pojo.getClass().getComponentType(); int len = Array.getLength(pojo); Collection dest = createCollection(type, len); history.put(pojo, dest); for (int i = 0; i < len; i ++) { Object obj = Array.get(pojo, i); Object value = realize0(obj, ctype, null, history); dest.add(value); } return dest; } else { Class<?> ctype = (type != null && type.isArray() ? type.getComponentType() : pojo.getClass().getComponentType()); int len = Array.getLength(pojo); Object dest = Array.newInstance(ctype, len); history.put(pojo, dest); for (int i = 0; i < len; i ++) { Object obj = Array.get(pojo, i); Object value = realize0(obj, ctype, null, history); Array.set(dest, i, value); } return dest; } } if (pojo instanceof Collection<?>) { if (type.isArray()) { Class<?> ctype = type.getComponentType(); Collection<Object> src = (Collection<Object>)pojo; int len = src.size(); Object dest = Array.newInstance(ctype, len); history.put(pojo, dest); int i = 0; for (Object obj : src) { Object value = realize0(obj, ctype, null, history); Array.set(dest, i, value); i ++; } return dest; } else { Collection<Object> src = (Collection<Object>)pojo; int len = src.size(); Collection<Object> dest = createCollection(type, len); history.put(pojo, dest); for (Object obj : src) { Type keyType = getGenericClassByIndex(genericType, 0); Class<?> keyClazz = obj.getClass() ; if ( keyType instanceof Class){ keyClazz = (Class<?>)keyType; } Object value = realize0(obj, keyClazz, keyType, history); dest.add(value); } return dest; } } if (pojo instanceof Map<?, ?> && type != null) { Object className = ((Map<Object, Object>)pojo).get("class"); if (className instanceof String) { try { type = ClassHelper.forName((String)className); } catch (ClassNotFoundException e) { // ignore } } Map<Object, Object> map ; // 返回值类型不是方法签名类型的子集 并且 不是接口类型 if (! type.isInterface() && ! type.isAssignableFrom(pojo.getClass())){ try { map = (Map<Object,Object>)type.newInstance(); } catch (Exception e) { //ignore error map = (Map<Object, Object>)pojo; } }else { map = (Map<Object, Object>)pojo; } if (Map.class.isAssignableFrom(type) || type == Object.class) { final Map<Object, Object> result = createMap(map); history.put(pojo, result); for (Map.Entry<Object, Object> entry : map.entrySet()) { Type keyType = getGenericClassByIndex(genericType, 0); Type valueType = getGenericClassByIndex(genericType, 1); Class<?> keyClazz; if ( keyType instanceof Class){ keyClazz = (Class<?>)keyType; } else { keyClazz = entry.getKey() == null ? null : entry.getKey().getClass(); } Class<?> valueClazz; if ( valueType instanceof Class){ valueClazz = (Class<?>)valueType; } else { valueClazz = entry.getValue() == null ? null : entry.getValue().getClass() ; } Object key = keyClazz == null ? entry.getKey() : realize0(entry.getKey(), keyClazz, keyType, history); Object value = valueClazz == null ? entry.getValue() : realize0(entry.getValue(), valueClazz, valueType, history); result.put(key, value); } return result; } else if (type.isInterface()) { Object dest = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[]{type}, new PojoInvocationHandler(map)); history.put(pojo, dest); return dest; } else { Object dest = newInstance(type); history.put(pojo, dest); for (Map.Entry<Object, Object> entry : map.entrySet()) { Object key = entry.getKey(); if (key instanceof String) { String name = (String) key; Object value = entry.getValue(); if (value != null) { Method method = getSetterMethod(dest.getClass(), name, value.getClass()); Field field = getField(dest.getClass(), name); if (method != null) { if (! method.isAccessible()) method.setAccessible(true); Type ptype = method.getGenericParameterTypes()[0]; value = realize0(value, method.getParameterTypes()[0], ptype, history); try { method.invoke(dest, value); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("Failed to set pojo " + dest.getClass().getSimpleName() + " property " + name + " value " + value + "(" + value.getClass() + "), cause: " + e.getMessage(), e); } } else if (field != null) { value = realize0(value, field.getType(), field.getGenericType(), history); try { field.set(dest, value); } catch (IllegalAccessException e) { throw new RuntimeException( new StringBuilder(32) .append("Failed to set filed ") .append(name) .append(" of pojo ") .append(dest.getClass().getName()) .append( " : " ) .append(e.getMessage()).toString(), e); } } } } } if (dest instanceof Throwable) { Object message = map.get("message"); if (message instanceof String) { try { Field filed = Throwable.class.getDeclaredField("detailMessage"); if(! filed.isAccessible()) { filed.setAccessible(true); } filed.set(dest, (String) message); } catch (Exception e) { } } } return dest; } } return pojo; } /** * 获取范型的类型 * @param genericType * @param index * @return List<Person> 返回Person.class ,Map<String,Person> index=0 返回String.class index=1 返回Person.class */ private static Type getGenericClassByIndex(Type genericType, int index){ Type clazz = null ; //范型参数转换 if (genericType instanceof ParameterizedType){ ParameterizedType t = (ParameterizedType)genericType; Type[] types = t.getActualTypeArguments(); clazz = types[index]; } return clazz; } private static Object newInstance(Class<?> cls) { try { return cls.newInstance(); } catch (Throwable t) { try { Constructor<?>[] constructors = cls.getConstructors(); if (constructors != null && constructors.length == 0) { throw new RuntimeException("Illegal constructor: " + cls.getName()); } Constructor<?> constructor = constructors[0]; if (constructor.getParameterTypes().length > 0) { for (Constructor<?> c : constructors) { if (c.getParameterTypes().length < constructor.getParameterTypes().length) { constructor = c; if (constructor.getParameterTypes().length == 0) { break; } } } } return constructor.newInstance(new Object[constructor.getParameterTypes().length]); } catch (InstantiationException e) { throw new RuntimeException(e.getMessage(), e); } catch (IllegalAccessException e) { throw new RuntimeException(e.getMessage(), e); } catch (InvocationTargetException e) { throw new RuntimeException(e.getMessage(), e); } } } private static Method getSetterMethod(Class<?> cls, String property, Class<?> valueCls) { String name = "set" + property.substring(0, 1).toUpperCase() + property.substring(1); Method method = NAME_METHODS_CACHE.get(cls.getName() + "." + name + "(" +valueCls.getName() + ")"); if(method == null){ try { method = cls.getMethod(name, valueCls); } catch (NoSuchMethodException e) { for (Method m : cls.getMethods()) { if (ReflectUtils.isBeanPropertyWriteMethod(m) && m.getName().equals(name)) { method = m; } } } if(method != null){ NAME_METHODS_CACHE.put(cls.getName() + "." + name + "(" +valueCls.getName() + ")", method); } } return method; } private static Field getField(Class<?> cls, String fieldName) { Field result = null; if (CLASS_FIELD_CACHE.containsKey(cls) && CLASS_FIELD_CACHE.get(cls).containsKey(fieldName)) { return CLASS_FIELD_CACHE.get(cls).get(fieldName); } try { result = cls.getField(fieldName); } catch (NoSuchFieldException e) { for(Field field : cls.getFields()) { if (fieldName.equals(field.getName()) && ReflectUtils.isPublicInstanceField(field)) { result = field; break; } } } if (result != null) { ConcurrentMap<String, Field> fields = CLASS_FIELD_CACHE.get(cls); if (fields == null) { fields = new ConcurrentHashMap<String, Field>(); CLASS_FIELD_CACHE.putIfAbsent(cls, fields); } fields = CLASS_FIELD_CACHE.get(cls); fields.putIfAbsent(fieldName, result); } return result; } public static boolean isPojo(Class<?> cls) { return ! ReflectUtils.isPrimitives(cls) && ! Collection.class.isAssignableFrom(cls) && ! Map.class.isAssignableFrom(cls); } }
CompatibleTypeUtils.java
/* * Copyright 1999-2011 Alibaba Group. * * 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.alibaba.dubbo.common.utils; import java.lang.reflect.Array; import java.math.BigDecimal; import java.math.BigInteger; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; /** * @author ding.lid */ public class CompatibleTypeUtils { private CompatibleTypeUtils() { } private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; /** * 兼容类型转换。null值是OK的。如果不需要转换,则返回原来的值。 * 进行的兼容类型转换如下:(基本类对应的Wrapper类型不再列出。) * <ul> * <li> String -> char, enum, Date * <li> byte, short, int, long -> byte, short, int, long * <li> float, double -> float, double * </ul> */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static Object compatibleTypeConvert(Object value, Class<?> type) { if(value == null || type == null || type.isAssignableFrom(value.getClass())) { return value; } if(value instanceof String) { String string = (String) value; if (char.class.equals(type) || Character.class.equals(type)) { if(string.length() != 1) { throw new IllegalArgumentException(String.format("CAN NOT convert String(%s) to char!" + " when convert String to char, the String MUST only 1 char.", string)); } return string.charAt(0); } else if(type.isEnum()) { return Enum.valueOf((Class<Enum>)type, string); } else if(type == BigInteger.class) { return new BigInteger(string); } else if(type == BigDecimal.class) { return new BigDecimal(string); } else if(type == Short.class || type == short.class) { return new Short(string); } else if(type == Integer.class || type == int.class) { return new Integer(string); } else if(type == Long.class || type == long.class) { return new Long(string); } else if(type == Double.class || type == double.class) { return new Double(string); } else if(type == Float.class || type == float.class) { return new Float(string); } else if(type == Byte.class || type == byte.class) { return new Byte(string); } else if(type == Boolean.class || type == boolean.class) { return new Boolean(string); } else if(type == Date.class) { try { return new SimpleDateFormat(DATE_FORMAT).parse((String) value); } catch (ParseException e) { throw new IllegalStateException("Failed to parse date " + value + " by format " + DATE_FORMAT + ", cause: " + e.getMessage(), e); } } else if (type == Class.class) { try { return ReflectUtils.name2class((String)value); } catch (ClassNotFoundException e) { throw new RuntimeException(e.getMessage(), e); } } } else if(value instanceof Number) { Number number = (Number) value; if (type == byte.class || type == Byte.class) { return number.byteValue(); } else if (type == short.class || type == Short.class) { return number.shortValue(); } else if (type == int.class || type == Integer.class) { return number.intValue(); } else if (type == long.class || type == Long.class) { return number.longValue(); } else if (type == float.class || type == Float.class) { return number.floatValue(); } else if (type == double.class || type == Double.class) { return number.doubleValue(); } else if (type == BigInteger.class) { return BigInteger.valueOf(number.longValue()); } else if (type == BigDecimal.class) { return BigDecimal.valueOf(number.doubleValue()); } else if (type == Date.class) { return new Date(number.longValue()); } } else if(value instanceof Collection) { Collection collection = (Collection) value; if (type.isArray()) { int length = collection.size(); Object array = Array.newInstance(type.getComponentType(), length); int i = 0; for (Object item : collection) { Array.set(array, i ++, item); } return array; } else if (! type.isInterface()) { try { Collection result = (Collection) type.newInstance(); result.addAll(collection); return result; } catch (Throwable e) { } } else if (type == List.class) { return new ArrayList<Object>(collection); } else if (type == Set.class) { return new HashSet<Object>(collection); } } else if(value.getClass().isArray() && Collection.class.isAssignableFrom(type)) { Collection collection; if (! type.isInterface()) { try { collection = (Collection) type.newInstance(); } catch (Throwable e) { collection = new ArrayList<Object>(); } } else if (type == Set.class) { collection = new HashSet<Object>(); } else { collection = new ArrayList<Object>(); } int length = Array.getLength(value); for (int i = 0; i < length; i ++) { collection.add(Array.get(value, i)); } return collection; } return value; } }ReflectUtils.java
/* * Copyright 1999-2011 Alibaba Group. * * 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.alibaba.dubbo.common.utils; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.GenericArrayType; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.net.URL; import java.security.CodeSource; import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import javassist.CtClass; import javassist.CtConstructor; import javassist.CtMethod; import javassist.NotFoundException; /** * ReflectUtils * * @author qian.lei */ public final class ReflectUtils { /** * void(V). */ public static final char JVM_VOID = 'V'; /** * boolean(Z). */ public static final char JVM_BOOLEAN = 'Z'; /** * byte(B). */ public static final char JVM_BYTE = 'B'; /** * char(C). */ public static final char JVM_CHAR = 'C'; /** * double(D). */ public static final char JVM_DOUBLE = 'D'; /** * float(F). */ public static final char JVM_FLOAT = 'F'; /** * int(I). */ public static final char JVM_INT = 'I'; /** * long(J). */ public static final char JVM_LONG = 'J'; /** * short(S). */ public static final char JVM_SHORT = 'S'; public static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0]; public static final String JAVA_IDENT_REGEX = "(?:[_$a-zA-Z][_$a-zA-Z0-9]*)"; public static final String JAVA_NAME_REGEX = "(?:" + JAVA_IDENT_REGEX + "(?:\\." + JAVA_IDENT_REGEX + ")*)"; public static final String CLASS_DESC = "(?:L" + JAVA_IDENT_REGEX + "(?:\\/" + JAVA_IDENT_REGEX + ")*;)"; public static final String ARRAY_DESC = "(?:\\[+(?:(?:[VZBCDFIJS])|" + CLASS_DESC + "))"; public static final String DESC_REGEX = "(?:(?:[VZBCDFIJS])|" + CLASS_DESC + "|" + ARRAY_DESC + ")"; public static final Pattern DESC_PATTERN = Pattern.compile(DESC_REGEX); public static final String METHOD_DESC_REGEX = "(?:("+JAVA_IDENT_REGEX+")?\\(("+DESC_REGEX+"*)\\)("+DESC_REGEX+")?)"; public static final Pattern METHOD_DESC_PATTERN = Pattern.compile(METHOD_DESC_REGEX); public static final Pattern GETTER_METHOD_DESC_PATTERN = Pattern.compile("get([A-Z][_a-zA-Z0-9]*)\\(\\)(" + DESC_REGEX + ")"); public static final Pattern SETTER_METHOD_DESC_PATTERN = Pattern.compile("set([A-Z][_a-zA-Z0-9]*)\\((" + DESC_REGEX + ")\\)V"); public static final Pattern IS_HAS_CAN_METHOD_DESC_PATTERN = Pattern.compile("(?:is|has|can)([A-Z][_a-zA-Z0-9]*)\\(\\)Z"); private static final ConcurrentMap<String, Class<?>> DESC_CLASS_CACHE = new ConcurrentHashMap<String, Class<?>>(); private static final ConcurrentMap<String, Class<?>> NAME_CLASS_CACHE = new ConcurrentHashMap<String, Class<?>>(); private static final ConcurrentMap<String, Method> Signature_METHODS_CACHE = new ConcurrentHashMap<String, Method>(); public static boolean isPrimitives(Class<?> cls) { if (cls.isArray()) { return isPrimitive(cls.getComponentType()); } return isPrimitive(cls); } public static boolean isPrimitive(Class<?> cls) { return cls.isPrimitive() || cls == String.class || cls == Boolean.class || cls == Character.class || Number.class.isAssignableFrom(cls) || Date.class.isAssignableFrom(cls); } public static Class<?> getBoxedClass(Class<?> c) { if( c == int.class ) c = Integer.class; else if( c == boolean.class ) c = Boolean.class; else if( c == long.class ) c = Long.class; else if( c == float.class ) c = Float.class; else if( c == double.class ) c = Double.class; else if( c == char.class ) c = Character.class; else if( c == byte.class ) c = Byte.class; else if( c == short.class ) c = Short.class; return c; } /** * is compatible. * * @param c class. * @param o instance. * @return compatible or not. */ public static boolean isCompatible(Class<?> c, Object o) { boolean pt = c.isPrimitive(); if( o == null ) return !pt; if( pt ) { if( c == int.class ) c = Integer.class; else if( c == boolean.class ) c = Boolean.class; else if( c == long.class ) c = Long.class; else if( c == float.class ) c = Float.class; else if( c == double.class ) c = Double.class; else if( c == char.class ) c = Character.class; else if( c == byte.class ) c = Byte.class; else if( c == short.class ) c = Short.class; } if( c == o.getClass() ) return true; return c.isInstance(o); } /** * is compatible. * * @param cs class array. * @param os object array. * @return compatible or not. */ public static boolean isCompatible(Class<?>[] cs, Object[] os) { int len = cs.length; if( len != os.length ) return false; if( len == 0 ) return true; for(int i=0;i<len;i++) if( !isCompatible(cs[i], os[i]) ) return false; return true; } public static String getCodeBase(Class<?> cls) { if (cls == null) return null; ProtectionDomain domain = cls.getProtectionDomain(); if (domain == null) return null; CodeSource source = domain.getCodeSource(); if (source == null) return null; URL location = source.getLocation(); if (location == null) return null; return location.getFile(); } /** * get name. * java.lang.Object[][].class => "java.lang.Object[][]" * * @param c class. * @return name. */ public static String getName(Class<?> c) { if( c.isArray() ) { StringBuilder sb = new StringBuilder(); do { sb.append("[]"); c = c.getComponentType(); } while( c.isArray() ); return c.getName() + sb.toString(); } return c.getName(); } public static Class<?> getGenericClass(Class<?> cls) { return getGenericClass(cls, 0); } public static Class<?> getGenericClass(Class<?> cls, int i) { try { ParameterizedType parameterizedType = ((ParameterizedType) cls.getGenericInterfaces()[0]); Object genericClass = parameterizedType.getActualTypeArguments()[i]; if (genericClass instanceof ParameterizedType) { // 处理多级泛型 return (Class<?>) ((ParameterizedType) genericClass).getRawType(); } else if (genericClass instanceof GenericArrayType) { // 处理数组泛型 return (Class<?>) ((GenericArrayType) genericClass).getGenericComponentType(); } else if (((Class)genericClass).isArray()) { // 在 JDK 7 以上的版本, Foo<int[]> 不再是 GenericArrayType return ((Class)genericClass).getComponentType(); } else { return (Class<?>) genericClass; } } catch (Throwable e) { throw new IllegalArgumentException(cls.getName() + " generic type undefined!", e); } } /** * get method name. * "void do(int)", "void do()", "int do(java.lang.String,boolean)" * * @param m method. * @return name. */ public static String getName(final Method m) { StringBuilder ret = new StringBuilder(); ret.append(getName(m.getReturnType())).append(' '); ret.append(m.getName()).append('('); Class<?>[] parameterTypes = m.getParameterTypes(); for(int i=0;i<parameterTypes.length;i++) { if( i > 0 ) ret.append(','); ret.append(getName(parameterTypes[i])); } ret.append(')'); return ret.toString(); } public static String getSignature(String methodName, Class<?>[] parameterTypes) { StringBuilder sb = new StringBuilder(methodName); sb.append("("); if (parameterTypes != null && parameterTypes.length > 0) { boolean first = true; for (Class<?> type : parameterTypes) { if (first) { first = false; } else { sb.append(","); } sb.append(type.getName()); } } sb.append(")"); return sb.toString(); } /** * get constructor name. * "()", "(java.lang.String,int)" * * @param c constructor. * @return name. */ public static String getName(final Constructor<?> c) { StringBuilder ret = new StringBuilder("("); Class<?>[] parameterTypes = c.getParameterTypes(); for(int i=0;i<parameterTypes.length;i++) { if( i > 0 ) ret.append(','); ret.append(getName(parameterTypes[i])); } ret.append(')'); return ret.toString(); } /** * get class desc. * boolean[].class => "[Z" * Object.class => "Ljava/lang/Object;" * * @param c class. * @return desc. * @throws NotFoundException */ public static String getDesc(Class<?> c) { StringBuilder ret = new StringBuilder(); while( c.isArray() ) { ret.append('['); c = c.getComponentType(); } if( c.isPrimitive() ) { String t = c.getName(); if( "void".equals(t) ) ret.append(JVM_VOID); else if( "boolean".equals(t) ) ret.append(JVM_BOOLEAN); else if( "byte".equals(t) ) ret.append(JVM_BYTE); else if( "char".equals(t) ) ret.append(JVM_CHAR); else if( "double".equals(t) ) ret.append(JVM_DOUBLE); else if( "float".equals(t) ) ret.append(JVM_FLOAT); else if( "int".equals(t) ) ret.append(JVM_INT); else if( "long".equals(t) ) ret.append(JVM_LONG); else if( "short".equals(t) ) ret.append(JVM_SHORT); } else { ret.append('L'); ret.append(c.getName().replace('.', '/')); ret.append(';'); } return ret.toString(); } /** * get class array desc. * [int.class, boolean[].class, Object.class] => "I[ZLjava/lang/Object;" * * @param cs class array. * @return desc. * @throws NotFoundException */ public static String getDesc(final Class<?>[] cs) { if( cs.length == 0 ) return ""; StringBuilder sb = new StringBuilder(64); for( Class<?> c : cs ) sb.append(getDesc(c)); return sb.toString(); } /** * get method desc. * int do(int arg1) => "do(I)I" * void do(String arg1,boolean arg2) => "do(Ljava/lang/String;Z)V" * * @param m method. * @return desc. */ public static String getDesc(final Method m) { StringBuilder ret = new StringBuilder(m.getName()).append('('); Class<?>[] parameterTypes = m.getParameterTypes(); for(int i=0;i<parameterTypes.length;i++) ret.append(getDesc(parameterTypes[i])); ret.append(')').append(getDesc(m.getReturnType())); return ret.toString(); } /** * get constructor desc. * "()V", "(Ljava/lang/String;I)V" * * @param c constructor. * @return desc */ public static String getDesc(final Constructor<?> c) { StringBuilder ret = new StringBuilder("("); Class<?>[] parameterTypes = c.getParameterTypes(); for(int i=0;i<parameterTypes.length;i++) ret.append(getDesc(parameterTypes[i])); ret.append(')').append('V'); return ret.toString(); } /** * get method desc. * "(I)I", "()V", "(Ljava/lang/String;Z)V" * * @param m method. * @return desc. */ public static String getDescWithoutMethodName(Method m) { StringBuilder ret = new StringBuilder(); ret.append('('); Class<?>[] parameterTypes = m.getParameterTypes(); for(int i=0;i<parameterTypes.length;i++) ret.append(getDesc(parameterTypes[i])); ret.append(')').append(getDesc(m.getReturnType())); return ret.toString(); } /** * get class desc. * Object.class => "Ljava/lang/Object;" * boolean[].class => "[Z" * * @param c class. * @return desc. * @throws NotFoundException */ public static String getDesc(final CtClass c) throws NotFoundException { StringBuilder ret = new StringBuilder(); if( c.isArray() ) { ret.append('['); ret.append(getDesc(c.getComponentType())); } else if( c.isPrimitive() ) { String t = c.getName(); if( "void".equals(t) ) ret.append(JVM_VOID); else if( "boolean".equals(t) ) ret.append(JVM_BOOLEAN); else if( "byte".equals(t) ) ret.append(JVM_BYTE); else if( "char".equals(t) ) ret.append(JVM_CHAR); else if( "double".equals(t) ) ret.append(JVM_DOUBLE); else if( "float".equals(t) ) ret.append(JVM_FLOAT); else if( "int".equals(t) ) ret.append(JVM_INT); else if( "long".equals(t) ) ret.append(JVM_LONG); else if( "short".equals(t) ) ret.append(JVM_SHORT); } else { ret.append('L'); ret.append(c.getName().replace('.','/')); ret.append(';'); } return ret.toString(); } /** * get method desc. * "do(I)I", "do()V", "do(Ljava/lang/String;Z)V" * * @param m method. * @return desc. */ public static String getDesc(final CtMethod m) throws NotFoundException { StringBuilder ret = new StringBuilder(m.getName()).append('('); CtClass[] parameterTypes = m.getParameterTypes(); for(int i=0;i<parameterTypes.length;i++) ret.append(getDesc(parameterTypes[i])); ret.append(')').append(getDesc(m.getReturnType())); return ret.toString(); } /** * get constructor desc. * "()V", "(Ljava/lang/String;I)V" * * @param c constructor. * @return desc */ public static String getDesc(final CtConstructor c) throws NotFoundException { StringBuilder ret = new StringBuilder("("); CtClass[] parameterTypes = c.getParameterTypes(); for(int i=0;i<parameterTypes.length;i++) ret.append(getDesc(parameterTypes[i])); ret.append(')').append('V'); return ret.toString(); } /** * get method desc. * "(I)I", "()V", "(Ljava/lang/String;Z)V". * * @param m method. * @return desc. */ public static String getDescWithoutMethodName(final CtMethod m) throws NotFoundException { StringBuilder ret = new StringBuilder(); ret.append('('); CtClass[] parameterTypes = m.getParameterTypes(); for(int i=0;i<parameterTypes.length;i++) ret.append(getDesc(parameterTypes[i])); ret.append(')').append(getDesc(m.getReturnType())); return ret.toString(); } /** * name to desc. * java.util.Map[][] => "[[Ljava/util/Map;" * * @param name name. * @return desc. */ public static String name2desc(String name) { StringBuilder sb = new StringBuilder(); int c = 0,index = name.indexOf('['); if( index > 0 ) { c = ( name.length() - index ) / 2; name = name.substring(0,index); } while( c-- > 0 ) sb.append("["); if( "void".equals(name) ) sb.append(JVM_VOID); else if( "boolean".equals(name) ) sb.append(JVM_BOOLEAN); else if( "byte".equals(name) ) sb.append(JVM_BYTE); else if( "char".equals(name) ) sb.append(JVM_CHAR); else if( "double".equals(name) ) sb.append(JVM_DOUBLE); else if( "float".equals(name) ) sb.append(JVM_FLOAT); else if( "int".equals(name) ) sb.append(JVM_INT); else if( "long".equals(name) ) sb.append(JVM_LONG); else if( "short".equals(name) ) sb.append(JVM_SHORT); else sb.append('L').append(name.replace('.', '/')).append(';'); return sb.toString(); } /** * desc to name. * "[[I" => "int[][]" * * @param desc desc. * @return name. */ public static String desc2name(String desc) { StringBuilder sb = new StringBuilder(); int c = desc.lastIndexOf('[') + 1; if( desc.length() == c+1 ) { switch( desc.charAt(c) ) { case JVM_VOID: { sb.append("void"); break; } case JVM_BOOLEAN: { sb.append("boolean"); break; } case JVM_BYTE: { sb.append("byte"); break; } case JVM_CHAR: { sb.append("char"); break; } case JVM_DOUBLE: { sb.append("double"); break; } case JVM_FLOAT: { sb.append("float"); break; } case JVM_INT: { sb.append("int"); break; } case JVM_LONG: { sb.append("long"); break; } case JVM_SHORT: { sb.append("short"); break; } default: throw new RuntimeException(); } } else { sb.append(desc.substring(c+1, desc.length()-1).replace('/','.')); } while( c-- > 0 ) sb.append("[]"); return sb.toString(); } public static Class<?> forName(String name) { try { return name2class(name); } catch (ClassNotFoundException e) { throw new IllegalStateException("Not found class " + name + ", cause: " + e.getMessage(), e); } } /** * name to class. * "boolean" => boolean.class * "java.util.Map[][]" => java.util.Map[][].class * * @param name name. * @return Class instance. */ public static Class<?> name2class(String name) throws ClassNotFoundException { return name2class(ClassHelper.getClassLoader(), name); } /** * name to class. * "boolean" => boolean.class * "java.util.Map[][]" => java.util.Map[][].class * * @param cl ClassLoader instance. * @param name name. * @return Class instance. */ private static Class<?> name2class(ClassLoader cl, String name) throws ClassNotFoundException { int c = 0, index = name.indexOf('['); if( index > 0 ) { c = ( name.length() - index ) / 2; name = name.substring(0, index); } if( c > 0 ) { StringBuilder sb = new StringBuilder(); while( c-- > 0 ) sb.append("["); if( "void".equals(name) ) sb.append(JVM_VOID); else if( "boolean".equals(name) ) sb.append(JVM_BOOLEAN); else if( "byte".equals(name) ) sb.append(JVM_BYTE); else if( "char".equals(name) ) sb.append(JVM_CHAR); else if( "double".equals(name) ) sb.append(JVM_DOUBLE); else if( "float".equals(name) ) sb.append(JVM_FLOAT); else if( "int".equals(name) ) sb.append(JVM_INT); else if( "long".equals(name) ) sb.append(JVM_LONG); else if( "short".equals(name) ) sb.append(JVM_SHORT); else sb.append('L').append(name).append(';'); // "java.lang.Object" ==> "Ljava.lang.Object;" name = sb.toString(); } else { if( "void".equals(name) ) return void.class; else if( "boolean".equals(name) ) return boolean.class; else if( "byte".equals(name) ) return byte.class; else if( "char".equals(name) ) return char.class; else if( "double".equals(name) ) return double.class; else if( "float".equals(name) ) return float.class; else if( "int".equals(name) ) return int.class; else if( "long".equals(name) ) return long.class; else if( "short".equals(name) ) return short.class; } if( cl == null ) cl = ClassHelper.getClassLoader(); Class<?> clazz = NAME_CLASS_CACHE.get(name); if(clazz == null){ clazz = Class.forName(name, true, cl); NAME_CLASS_CACHE.put(name, clazz); } return clazz; } /** * desc to class. * "[Z" => boolean[].class * "[[Ljava/util/Map;" => java.util.Map[][].class * * @param desc desc. * @return Class instance. * @throws ClassNotFoundException */ public static Class<?> desc2class(String desc) throws ClassNotFoundException { return desc2class(ClassHelper.getClassLoader(), desc); } /** * desc to class. * "[Z" => boolean[].class * "[[Ljava/util/Map;" => java.util.Map[][].class * * @param cl ClassLoader instance. * @param desc desc. * @return Class instance. * @throws ClassNotFoundException */ private static Class<?> desc2class(ClassLoader cl, String desc) throws ClassNotFoundException { switch( desc.charAt(0) ) { case JVM_VOID: return void.class; case JVM_BOOLEAN: return boolean.class; case JVM_BYTE: return byte.class; case JVM_CHAR: return char.class; case JVM_DOUBLE: return double.class; case JVM_FLOAT: return float.class; case JVM_INT: return int.class; case JVM_LONG: return long.class; case JVM_SHORT: return short.class; case 'L': desc = desc.substring(1, desc.length()-1).replace('/', '.'); // "Ljava/lang/Object;" ==> "java.lang.Object" break; case '[': desc = desc.replace('/', '.'); // "[[Ljava/lang/Object;" ==> "[[Ljava.lang.Object;" break; default: throw new ClassNotFoundException("Class not found: " + desc); } if( cl == null ) cl = ClassHelper.getClassLoader(); Class<?> clazz = DESC_CLASS_CACHE.get(desc); if(clazz==null){ clazz = Class.forName(desc, true, cl); DESC_CLASS_CACHE.put(desc, clazz); } return clazz; } /** * get class array instance. * * @param desc desc. * @return Class class array. * @throws ClassNotFoundException */ public static Class<?>[] desc2classArray(String desc) throws ClassNotFoundException { Class<?>[] ret = desc2classArray(ClassHelper.getClassLoader(), desc); return ret; } /** * get class array instance. * * @param cl ClassLoader instance. * @param desc desc. * @return Class[] class array. * @throws ClassNotFoundException */ private static Class<?>[] desc2classArray(ClassLoader cl, String desc) throws ClassNotFoundException { if( desc.length() == 0 ) return EMPTY_CLASS_ARRAY; List<Class<?>> cs = new ArrayList<Class<?>>(); Matcher m = DESC_PATTERN.matcher(desc); while(m.find()) cs.add(desc2class(cl, m.group())); return cs.toArray(EMPTY_CLASS_ARRAY); } /** * 根据方法签名从类中找出方法。 * * @param clazz 查找的类。 * @param methodName 方法签名,形如method1(int, String)。也允许只给方法名不参数只有方法名,形如method2。 * @return 返回查找到的方法。 * @throws NoSuchMethodException * @throws ClassNotFoundException * @throws IllegalStateException 给定的方法签名找到多个方法(方法签名中没有指定参数,又有有重载的方法的情况) */ public static Method findMethodByMethodSignature(Class<?> clazz, String methodName, String[] parameterTypes) throws NoSuchMethodException, ClassNotFoundException { String signature = clazz.getName() + "." + methodName; if(parameterTypes != null && parameterTypes.length > 0){ signature += StringUtils.join(parameterTypes); } Method method = Signature_METHODS_CACHE.get(signature); if(method != null){ return method; } if (parameterTypes == null) { List<Method> finded = new ArrayList<Method>(); for (Method m : clazz.getMethods()) { if (m.getName().equals(methodName)) { finded.add(m); } } if (finded.isEmpty()) { throw new NoSuchMethodException("No such method " + methodName + " in class " + clazz); } if(finded.size() > 1) { String msg = String.format("Not unique method for method name(%s) in class(%s), find %d methods.", methodName, clazz.getName(), finded.size()); throw new IllegalStateException(msg); } method = finded.get(0); } else { Class<?>[] types = new Class<?>[parameterTypes.length]; for (int i = 0; i < parameterTypes.length; i ++) { types[i] = ReflectUtils.name2class(parameterTypes[i]); } method = clazz.getMethod(methodName, types); } Signature_METHODS_CACHE.put(signature, method); return method; } public static Method findMethodByMethodName(Class<?> clazz, String methodName) throws NoSuchMethodException, ClassNotFoundException { return findMethodByMethodSignature(clazz, methodName, null); } public static Constructor<?> findConstructor(Class<?> clazz, Class<?> paramType) throws NoSuchMethodException { Constructor<?> targetConstructor; try { targetConstructor = clazz.getConstructor(new Class<?>[] {paramType}); } catch (NoSuchMethodException e) { targetConstructor = null; Constructor<?>[] constructors = clazz.getConstructors(); for (Constructor<?> constructor : constructors) { if (Modifier.isPublic(constructor.getModifiers()) && constructor.getParameterTypes().length == 1 && constructor.getParameterTypes()[0].isAssignableFrom(paramType)) { targetConstructor = constructor; break; } } if (targetConstructor == null) { throw e; } } return targetConstructor; } /** * 检查对象是否是指定接口的实现。 * <p> * 不会触发到指定接口的{@link Class},所以如果ClassLoader中没有指定接口类时,也不会出错。 * * @param obj 要检查的对象 * @param interfaceClazzName 指定的接口名 * @return 返回{@code true},如果对象实现了指定接口;否则返回{@code false}。 */ public static boolean isInstance(Object obj, String interfaceClazzName) { for (Class<?> clazz = obj.getClass(); clazz != null && !clazz.equals(Object.class); clazz = clazz.getSuperclass()) { Class<?>[] interfaces = clazz.getInterfaces(); for (Class<?> itf : interfaces) { if (itf.getName().equals(interfaceClazzName)) { return true; } } } return false; } public static Object getEmptyObject(Class<?> returnType) { return getEmptyObject(returnType, new HashMap<Class<?>, Object>(), 0); } private static Object getEmptyObject(Class<?> returnType, Map<Class<?>, Object> emptyInstances, int level) { if (level > 2) return null; if (returnType == null) { return null; } else if (returnType == boolean.class || returnType == Boolean.class) { return false; } else if (returnType == char.class || returnType == Character.class) { return '\0'; } else if (returnType == byte.class || returnType == Byte.class) { return (byte)0; } else if (returnType == short.class || returnType == Short.class) { return (short)0; } else if (returnType == int.class || returnType == Integer.class) { return 0; } else if (returnType == long.class || returnType == Long.class) { return 0L; } else if (returnType == float.class || returnType == Float.class) { return 0F; } else if (returnType == double.class || returnType == Double.class) { return 0D; } else if (returnType.isArray()) { return Array.newInstance(returnType.getComponentType(), 0); } else if (returnType.isAssignableFrom(ArrayList.class)) { return new ArrayList<Object>(0); } else if (returnType.isAssignableFrom(HashSet.class)) { return new HashSet<Object>(0); } else if (returnType.isAssignableFrom(HashMap.class)) { return new HashMap<Object, Object>(0); } else if (String.class.equals(returnType)) { return ""; } else if (! returnType.isInterface()) { try { Object value = emptyInstances.get(returnType); if (value == null) { value = returnType.newInstance(); emptyInstances.put(returnType, value); } Class<?> cls = value.getClass(); while (cls != null && cls != Object.class) { Field[] fields = cls.getDeclaredFields(); for (Field field : fields) { Object property = getEmptyObject(field.getType(), emptyInstances, level + 1); if (property != null) { try { if (! field.isAccessible()) { field.setAccessible(true); } field.set(value, property); } catch (Throwable e) { } } } cls = cls.getSuperclass(); } return value; } catch (Throwable e) { return null; } } else { return null; } } public static boolean isBeanPropertyReadMethod(Method method) { return method != null && Modifier.isPublic(method.getModifiers()) && ! Modifier.isStatic(method.getModifiers()) && method.getReturnType() != void.class && method.getDeclaringClass() != Object.class && method.getParameterTypes().length == 0 && ((method.getName().startsWith("get") && method.getName().length() > 3) || (method.getName().startsWith("is") && method.getName().length() > 2)); } public static String getPropertyNameFromBeanReadMethod(Method method) { if (isBeanPropertyReadMethod(method)) { if (method.getName().startsWith("get")) { return method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4); } if (method.getName().startsWith("is")) { return method.getName().substring(2, 3).toLowerCase() + method.getName().substring(3); } } return null; } public static boolean isBeanPropertyWriteMethod(Method method) { return method != null && Modifier.isPublic(method.getModifiers()) && ! Modifier.isStatic(method.getModifiers()) && method.getDeclaringClass() != Object.class && method.getParameterTypes().length == 1 && method.getName().startsWith("set") && method.getName().length() > 3; } public static String getPropertyNameFromBeanWriteMethod(Method method) { if (isBeanPropertyWriteMethod(method)) { return method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4); } return null; } public static boolean isPublicInstanceField(Field field) { return Modifier.isPublic(field.getModifiers()) && !Modifier.isStatic(field.getModifiers()) && !Modifier.isFinal(field.getModifiers()) && !field.isSynthetic(); } public static Map<String, Field> getBeanPropertyFields(Class cl) { Map<String, Field> properties = new HashMap<String, Field>(); for(; cl != null; cl = cl.getSuperclass()) { Field[] fields = cl.getDeclaredFields(); for(Field field : fields) { if (Modifier.isTransient(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) { continue; } field.setAccessible(true); properties.put(field.getName(), field); } } return properties; } public static Map<String, Method> getBeanPropertyReadMethods(Class cl) { Map<String, Method> properties = new HashMap<String, Method>(); for(; cl != null; cl = cl.getSuperclass()) { Method[] methods = cl.getDeclaredMethods(); for(Method method : methods) { if (isBeanPropertyReadMethod(method)) { method.setAccessible(true); String property = getPropertyNameFromBeanReadMethod(method); properties.put(property, method); } } } return properties; } private ReflectUtils(){} }
OK,大功告成。。。。
相关文章推荐
- 部署DTCMS到Jexus遇到的问题及解决思路---Linux环境搭建
- Java GC机制及原理 项目实际遇到GC问题解决思路和经验总结
- 黑马程序员————java环境搭建过程中遇到的问题与解决思考
- JAVA学习之一——在DOS环境下编译遇到的问题及解决方法
- 今天遇到关于JAVA INTEGER类型的问题 不过还好 现在解决了,
- java实现插入mysql二进制文件,blob类型,遇到问题及解决办法
- 实验过程中遇到的mysql DateTime类型与java Calendar问题与解决过程记录
- JSON(3):Java的Date类型转换为符合json语法的字符串遇到的问题及其解决办法
- java开发遇到的问题,及其解决思路(知识点备份)
- java 解决分布式环境中 高并发环境下数据插入重复问题
- Java与Android开发环境配置以及遇到的问题解决
- java实现插入mysql二进制文件,blob类型,遇到问题及解决办法
- Java使用Oracle遇到的最大游标超出问题及其解决方法
- 搭建ubuntu环境时遇到的问题及解决方法
- 烦人的java jdk 环境变量问题(2小步解决的事儿)
- win10配置java环境变量,解决javac不是内部或外部命令等问题
- Java使用Oracle遇到的最大游标超出问题及其解决方法
- 部署DTCMS到Jexus遇到的问题及解决思路--验证码
- Java环境配置出现的问题及解决办法