com.landawn.abacus.util.ClassUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of abacus-android Show documentation
Show all versions of abacus-android Show documentation
A general and simple library for Android
/*
* Copyright (C) 2017 HaiYang Li
*
* 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.landawn.abacus.util;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.Writer;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URL;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.NClob;
import java.sql.RowId;
import java.sql.SQLXML;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.Enumeration;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.Stack;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Vector;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import javax.xml.datatype.XMLGregorianCalendar;
import com.landawn.abacus.DataSet;
import com.landawn.abacus.DirtyMarker;
import com.landawn.abacus.annotation.Id;
import com.landawn.abacus.annotation.ReadOnlyId;
import com.landawn.abacus.condition.Condition;
import com.landawn.abacus.core.NameUtil;
import com.landawn.abacus.core.RowDataSet;
import com.landawn.abacus.exception.UncheckedIOException;
import com.landawn.abacus.logging.Logger;
import com.landawn.abacus.logging.LoggerFactory;
import com.landawn.abacus.parser.ParserUtil;
import com.landawn.abacus.type.ObjectType;
import com.landawn.abacus.type.Type;
import com.landawn.abacus.type.TypeFactory;
import com.landawn.abacus.util.Tuple.Tuple1;
import com.landawn.abacus.util.Tuple.Tuple2;
import com.landawn.abacus.util.Tuple.Tuple3;
import com.landawn.abacus.util.Tuple.Tuple4;
import com.landawn.abacus.util.Tuple.Tuple5;
import com.landawn.abacus.util.Tuple.Tuple6;
import com.landawn.abacus.util.Tuple.Tuple7;
import com.landawn.abacus.util.Tuple.Tuple8;
import com.landawn.abacus.util.Tuple.Tuple9;
import com.landawn.abacus.util.u.Nullable;
import com.landawn.abacus.util.u.Optional;
import com.landawn.abacus.util.u.OptionalBoolean;
import com.landawn.abacus.util.u.OptionalByte;
import com.landawn.abacus.util.u.OptionalChar;
import com.landawn.abacus.util.u.OptionalDouble;
import com.landawn.abacus.util.u.OptionalFloat;
import com.landawn.abacus.util.u.OptionalInt;
import com.landawn.abacus.util.u.OptionalLong;
import com.landawn.abacus.util.u.OptionalShort;
/**
*
* @since 0.9
*
* @author Haiyang Li
*/
public final class ClassUtil {
private ClassUtil() {
// singleton
}
private static final Logger logger = LoggerFactory.getLogger(ClassUtil.class);
private static final String JAR_POSTFIX = ".jar";
private static final String CLASS_POSTFIX = ".class";
// ...
private static final String PROP_NAME_SEPARATOR = ".";
// ...
private static final String GET = "get".intern();
private static final String SET = "set".intern();
private static final String IS = "is".intern();
private static final String HAS = "has".intern();
// ... it has to be big enough to make it's safety to add element to
// ArrayBlockingQueue.
private static final int POOL_SIZE = Internals.POOL_SIZE;
// ...
private static final Map, Boolean> entityClassPool = new ObjectPool<>(POOL_SIZE);
private static final Map, Boolean> dirtyMarkerClassPool = new ObjectPool<>(POOL_SIZE);
// formalized property name list.
private static final Map> BUILT_IN_TYPE = new ObjectPool<>(POOL_SIZE); // new LinkedHashMap<>();
static {
BUILT_IN_TYPE.put(boolean.class.getCanonicalName(), boolean.class);
BUILT_IN_TYPE.put(char.class.getCanonicalName(), char.class);
BUILT_IN_TYPE.put(byte.class.getCanonicalName(), byte.class);
BUILT_IN_TYPE.put(short.class.getCanonicalName(), short.class);
BUILT_IN_TYPE.put(int.class.getCanonicalName(), int.class);
BUILT_IN_TYPE.put(long.class.getCanonicalName(), long.class);
BUILT_IN_TYPE.put(float.class.getCanonicalName(), float.class);
BUILT_IN_TYPE.put(double.class.getCanonicalName(), double.class);
BUILT_IN_TYPE.put(Boolean.class.getCanonicalName(), Boolean.class);
BUILT_IN_TYPE.put(Character.class.getCanonicalName(), Character.class);
BUILT_IN_TYPE.put(Byte.class.getCanonicalName(), Byte.class);
BUILT_IN_TYPE.put(Short.class.getCanonicalName(), Short.class);
BUILT_IN_TYPE.put(Integer.class.getCanonicalName(), Integer.class);
BUILT_IN_TYPE.put(Long.class.getCanonicalName(), Long.class);
BUILT_IN_TYPE.put(Float.class.getCanonicalName(), Float.class);
BUILT_IN_TYPE.put(Double.class.getCanonicalName(), Double.class);
BUILT_IN_TYPE.put(String.class.getCanonicalName(), String.class);
BUILT_IN_TYPE.put(Enum.class.getCanonicalName(), Enum.class);
BUILT_IN_TYPE.put(Class.class.getCanonicalName(), Class.class);
BUILT_IN_TYPE.put(Object.class.getCanonicalName(), Object.class);
BUILT_IN_TYPE.put(BigInteger.class.getCanonicalName(), BigInteger.class);
BUILT_IN_TYPE.put(BigDecimal.class.getCanonicalName(), BigDecimal.class);
BUILT_IN_TYPE.put(java.util.Date.class.getCanonicalName(), java.util.Date.class);
BUILT_IN_TYPE.put(Calendar.class.getCanonicalName(), Calendar.class);
BUILT_IN_TYPE.put(GregorianCalendar.class.getCanonicalName(), GregorianCalendar.class);
BUILT_IN_TYPE.put(XMLGregorianCalendar.class.getCanonicalName(), XMLGregorianCalendar.class);
BUILT_IN_TYPE.put(Collection.class.getCanonicalName(), Collection.class);
BUILT_IN_TYPE.put(List.class.getCanonicalName(), List.class);
BUILT_IN_TYPE.put(ArrayList.class.getCanonicalName(), ArrayList.class);
BUILT_IN_TYPE.put(LinkedList.class.getCanonicalName(), LinkedList.class);
BUILT_IN_TYPE.put(Stack.class.getCanonicalName(), Stack.class);
BUILT_IN_TYPE.put(Vector.class.getCanonicalName(), Vector.class);
BUILT_IN_TYPE.put(Set.class.getCanonicalName(), Set.class);
BUILT_IN_TYPE.put(HashSet.class.getCanonicalName(), HashSet.class);
BUILT_IN_TYPE.put(LinkedHashSet.class.getCanonicalName(), LinkedHashSet.class);
BUILT_IN_TYPE.put(SortedSet.class.getCanonicalName(), SortedSet.class);
BUILT_IN_TYPE.put(NavigableSet.class.getCanonicalName(), NavigableSet.class);
BUILT_IN_TYPE.put(TreeSet.class.getCanonicalName(), TreeSet.class);
BUILT_IN_TYPE.put(Queue.class.getCanonicalName(), Queue.class);
BUILT_IN_TYPE.put(Deque.class.getCanonicalName(), Deque.class);
BUILT_IN_TYPE.put(BlockingDeque.class.getCanonicalName(), BlockingDeque.class);
BUILT_IN_TYPE.put(ArrayDeque.class.getCanonicalName(), ArrayDeque.class);
BUILT_IN_TYPE.put(ArrayBlockingQueue.class.getCanonicalName(), ArrayBlockingQueue.class);
BUILT_IN_TYPE.put(LinkedBlockingQueue.class.getCanonicalName(), LinkedBlockingQueue.class);
BUILT_IN_TYPE.put(ConcurrentLinkedQueue.class.getCanonicalName(), ConcurrentLinkedQueue.class);
BUILT_IN_TYPE.put(LinkedBlockingDeque.class.getCanonicalName(), LinkedBlockingDeque.class);
BUILT_IN_TYPE.put(ConcurrentLinkedDeque.class.getCanonicalName(), ConcurrentLinkedDeque.class);
BUILT_IN_TYPE.put(PriorityQueue.class.getCanonicalName(), PriorityQueue.class);
BUILT_IN_TYPE.put(DelayQueue.class.getCanonicalName(), DelayQueue.class);
BUILT_IN_TYPE.put(Map.class.getCanonicalName(), Map.class);
BUILT_IN_TYPE.put(HashMap.class.getCanonicalName(), HashMap.class);
BUILT_IN_TYPE.put(LinkedHashMap.class.getCanonicalName(), LinkedHashMap.class);
BUILT_IN_TYPE.put(IdentityHashMap.class.getCanonicalName(), IdentityHashMap.class);
BUILT_IN_TYPE.put(ConcurrentMap.class.getCanonicalName(), ConcurrentMap.class);
BUILT_IN_TYPE.put(ConcurrentHashMap.class.getCanonicalName(), ConcurrentHashMap.class);
BUILT_IN_TYPE.put(SortedMap.class.getCanonicalName(), SortedMap.class);
BUILT_IN_TYPE.put(NavigableMap.class.getCanonicalName(), NavigableMap.class);
BUILT_IN_TYPE.put(TreeMap.class.getCanonicalName(), TreeMap.class);
BUILT_IN_TYPE.put(Iterator.class.getCanonicalName(), Iterator.class);
BUILT_IN_TYPE.put(File.class.getCanonicalName(), File.class);
BUILT_IN_TYPE.put(InputStream.class.getCanonicalName(), InputStream.class);
BUILT_IN_TYPE.put(ByteArrayInputStream.class.getCanonicalName(), ByteArrayInputStream.class);
BUILT_IN_TYPE.put(FileInputStream.class.getCanonicalName(), FileInputStream.class);
BUILT_IN_TYPE.put(OutputStream.class.getCanonicalName(), OutputStream.class);
BUILT_IN_TYPE.put(ByteArrayOutputStream.class.getCanonicalName(), ByteArrayOutputStream.class);
BUILT_IN_TYPE.put(FileOutputStream.class.getCanonicalName(), FileOutputStream.class);
BUILT_IN_TYPE.put(Reader.class.getCanonicalName(), Reader.class);
BUILT_IN_TYPE.put(StringReader.class.getCanonicalName(), StringReader.class);
BUILT_IN_TYPE.put(FileReader.class.getCanonicalName(), FileReader.class);
BUILT_IN_TYPE.put(InputStreamReader.class.getCanonicalName(), InputStreamReader.class);
BUILT_IN_TYPE.put(Writer.class.getCanonicalName(), Writer.class);
BUILT_IN_TYPE.put(StringWriter.class.getCanonicalName(), StringWriter.class);
BUILT_IN_TYPE.put(FileWriter.class.getCanonicalName(), FileWriter.class);
BUILT_IN_TYPE.put(OutputStreamWriter.class.getCanonicalName(), OutputStreamWriter.class);
BUILT_IN_TYPE.put(Date.class.getCanonicalName(), Date.class);
BUILT_IN_TYPE.put(Time.class.getCanonicalName(), Time.class);
BUILT_IN_TYPE.put(Timestamp.class.getCanonicalName(), Timestamp.class);
BUILT_IN_TYPE.put(Blob.class.getCanonicalName(), Blob.class);
BUILT_IN_TYPE.put(Clob.class.getCanonicalName(), Clob.class);
BUILT_IN_TYPE.put(NClob.class.getCanonicalName(), NClob.class);
BUILT_IN_TYPE.put(SQLXML.class.getCanonicalName(), SQLXML.class);
BUILT_IN_TYPE.put(RowId.class.getCanonicalName(), RowId.class);
BUILT_IN_TYPE.put(URL.class.getCanonicalName(), URL.class);
BUILT_IN_TYPE.put(BooleanList.class.getCanonicalName(), BooleanList.class);
BUILT_IN_TYPE.put(CharList.class.getCanonicalName(), CharList.class);
BUILT_IN_TYPE.put(ByteList.class.getCanonicalName(), ByteList.class);
BUILT_IN_TYPE.put(ShortList.class.getCanonicalName(), ShortList.class);
BUILT_IN_TYPE.put(IntList.class.getCanonicalName(), IntList.class);
BUILT_IN_TYPE.put(LongList.class.getCanonicalName(), LongList.class);
BUILT_IN_TYPE.put(FloatList.class.getCanonicalName(), FloatList.class);
BUILT_IN_TYPE.put(DoubleList.class.getCanonicalName(), DoubleList.class);
BUILT_IN_TYPE.put(MutableBoolean.class.getCanonicalName(), MutableBoolean.class);
BUILT_IN_TYPE.put(MutableChar.class.getCanonicalName(), MutableChar.class);
BUILT_IN_TYPE.put(MutableByte.class.getCanonicalName(), MutableByte.class);
BUILT_IN_TYPE.put(MutableShort.class.getCanonicalName(), MutableShort.class);
BUILT_IN_TYPE.put(MutableInt.class.getCanonicalName(), MutableInt.class);
BUILT_IN_TYPE.put(MutableLong.class.getCanonicalName(), MutableLong.class);
BUILT_IN_TYPE.put(MutableFloat.class.getCanonicalName(), MutableFloat.class);
BUILT_IN_TYPE.put(MutableDouble.class.getCanonicalName(), MutableDouble.class);
BUILT_IN_TYPE.put(OptionalBoolean.class.getCanonicalName(), OptionalBoolean.class);
BUILT_IN_TYPE.put(OptionalChar.class.getCanonicalName(), OptionalChar.class);
BUILT_IN_TYPE.put(OptionalByte.class.getCanonicalName(), OptionalByte.class);
BUILT_IN_TYPE.put(OptionalShort.class.getCanonicalName(), OptionalShort.class);
BUILT_IN_TYPE.put(OptionalInt.class.getCanonicalName(), OptionalInt.class);
BUILT_IN_TYPE.put(OptionalLong.class.getCanonicalName(), OptionalLong.class);
BUILT_IN_TYPE.put(OptionalFloat.class.getCanonicalName(), OptionalFloat.class);
BUILT_IN_TYPE.put(OptionalDouble.class.getCanonicalName(), OptionalDouble.class);
BUILT_IN_TYPE.put(Nullable.class.getCanonicalName(), Nullable.class);
BUILT_IN_TYPE.put(Optional.class.getCanonicalName(), Optional.class);
BUILT_IN_TYPE.put(Fraction.class.getCanonicalName(), Fraction.class);
BUILT_IN_TYPE.put(Range.class.getCanonicalName(), Range.class);
BUILT_IN_TYPE.put(Duration.class.getCanonicalName(), Duration.class);
BUILT_IN_TYPE.put(Pair.class.getCanonicalName(), Pair.class);
BUILT_IN_TYPE.put(BooleanPair.class.getCanonicalName(), BooleanPair.class);
BUILT_IN_TYPE.put(CharPair.class.getCanonicalName(), CharPair.class);
BUILT_IN_TYPE.put(BytePair.class.getCanonicalName(), BytePair.class);
BUILT_IN_TYPE.put(ShortPair.class.getCanonicalName(), ShortPair.class);
BUILT_IN_TYPE.put(IntPair.class.getCanonicalName(), IntPair.class);
BUILT_IN_TYPE.put(LongPair.class.getCanonicalName(), LongPair.class);
BUILT_IN_TYPE.put(FloatPair.class.getCanonicalName(), FloatPair.class);
BUILT_IN_TYPE.put(DoublePair.class.getCanonicalName(), DoublePair.class);
BUILT_IN_TYPE.put(Triple.class.getCanonicalName(), Triple.class);
BUILT_IN_TYPE.put(BooleanTriple.class.getCanonicalName(), BooleanTriple.class);
BUILT_IN_TYPE.put(CharTriple.class.getCanonicalName(), CharTriple.class);
BUILT_IN_TYPE.put(ByteTriple.class.getCanonicalName(), ByteTriple.class);
BUILT_IN_TYPE.put(ShortTriple.class.getCanonicalName(), ShortTriple.class);
BUILT_IN_TYPE.put(IntTriple.class.getCanonicalName(), IntTriple.class);
BUILT_IN_TYPE.put(LongTriple.class.getCanonicalName(), LongTriple.class);
BUILT_IN_TYPE.put(FloatTriple.class.getCanonicalName(), FloatTriple.class);
BUILT_IN_TYPE.put(DoubleTriple.class.getCanonicalName(), DoubleTriple.class);
BUILT_IN_TYPE.put(Tuple.class.getCanonicalName(), Tuple.class);
BUILT_IN_TYPE.put(Tuple1.class.getCanonicalName(), Tuple1.class);
BUILT_IN_TYPE.put(Tuple2.class.getCanonicalName(), Tuple2.class);
BUILT_IN_TYPE.put(Tuple3.class.getCanonicalName(), Tuple3.class);
BUILT_IN_TYPE.put(Tuple4.class.getCanonicalName(), Tuple4.class);
BUILT_IN_TYPE.put(Tuple5.class.getCanonicalName(), Tuple5.class);
BUILT_IN_TYPE.put(Tuple6.class.getCanonicalName(), Tuple6.class);
BUILT_IN_TYPE.put(Tuple7.class.getCanonicalName(), Tuple7.class);
BUILT_IN_TYPE.put(Tuple8.class.getCanonicalName(), Tuple8.class);
BUILT_IN_TYPE.put(Tuple9.class.getCanonicalName(), Tuple9.class);
BUILT_IN_TYPE.put(ArrayHashMap.class.getCanonicalName(), ArrayHashMap.class);
BUILT_IN_TYPE.put(LinkedArrayHashMap.class.getCanonicalName(), LinkedArrayHashMap.class);
BUILT_IN_TYPE.put(ArrayHashSet.class.getCanonicalName(), ArrayHashSet.class);
BUILT_IN_TYPE.put(LinkedArrayHashSet.class.getCanonicalName(), LinkedArrayHashSet.class);
BUILT_IN_TYPE.put(BiMap.class.getCanonicalName(), BiMap.class);
BUILT_IN_TYPE.put(ListMultimap.class.getCanonicalName(), ListMultimap.class);
BUILT_IN_TYPE.put(SetMultimap.class.getCanonicalName(), SetMultimap.class);
BUILT_IN_TYPE.put(Multimap.class.getCanonicalName(), Multimap.class);
BUILT_IN_TYPE.put(Multiset.class.getCanonicalName(), Multiset.class);
BUILT_IN_TYPE.put(LongMultiset.class.getCanonicalName(), LongMultiset.class);
BUILT_IN_TYPE.put(Sheet.class.getCanonicalName(), Sheet.class);
BUILT_IN_TYPE.put(HBaseColumn.class.getCanonicalName(), HBaseColumn.class);
BUILT_IN_TYPE.put(Type.class.getCanonicalName(), Type.class);
BUILT_IN_TYPE.put(Condition.class.getCanonicalName(), Condition.class);
BUILT_IN_TYPE.put(DataSet.class.getCanonicalName(), DataSet.class);
BUILT_IN_TYPE.put(RowDataSet.class.getCanonicalName(), RowDataSet.class);
//
BUILT_IN_TYPE.put(Map.Entry.class.getCanonicalName(), Map.Entry.class);
BUILT_IN_TYPE.put("java.util.Map.Entry", Map.Entry.class);
BUILT_IN_TYPE.put("Map.Entry", Map.Entry.class);
List> classes = new ArrayList<>(BUILT_IN_TYPE.values());
for (Class> cls : classes) {
Class> arrayClass = cls;
for (int i = 0; i < 7; i++) {
arrayClass = java.lang.reflect.Array.newInstance(arrayClass, 0).getClass();
BUILT_IN_TYPE.put(arrayClass.getCanonicalName(), arrayClass);
}
}
classes = new ArrayList<>(BUILT_IN_TYPE.values());
for (Class> cls : classes) {
if (cls.getCanonicalName().startsWith("java.util.Date")) {
continue;
}
BUILT_IN_TYPE.put(cls.getSimpleName(), cls);
}
//
// N.println("#########################################Builtin types================================");
// N.println("size = " + BUILT_IN_TYPE.size());
//
// for (Map.Entry> entry : BUILT_IN_TYPE.entrySet()) {
// N.println(entry.getKey() + " = " + entry.getValue());
// }
}
private static Map SYMBOL_OF_PRIMITIVE_ARRAY_CLASS_NAME = new HashMap<>();
static {
SYMBOL_OF_PRIMITIVE_ARRAY_CLASS_NAME.put(boolean.class.getName(), "Z");
SYMBOL_OF_PRIMITIVE_ARRAY_CLASS_NAME.put(char.class.getName(), "C");
SYMBOL_OF_PRIMITIVE_ARRAY_CLASS_NAME.put(byte.class.getName(), "B");
SYMBOL_OF_PRIMITIVE_ARRAY_CLASS_NAME.put(short.class.getName(), "S");
SYMBOL_OF_PRIMITIVE_ARRAY_CLASS_NAME.put(int.class.getName(), "I");
SYMBOL_OF_PRIMITIVE_ARRAY_CLASS_NAME.put(long.class.getName(), "J");
SYMBOL_OF_PRIMITIVE_ARRAY_CLASS_NAME.put(float.class.getName(), "F");
SYMBOL_OF_PRIMITIVE_ARRAY_CLASS_NAME.put(double.class.getName(), "D");
}
private static final Map camelCasePropNamePool = new ObjectPool<>(POOL_SIZE * 2);
private static final Map lowerCaseWithUnderscorePropNamePool = new ObjectPool<>(POOL_SIZE * 2);
private static final Map upperCaseWithUnderscorePropNamePool = new ObjectPool<>(POOL_SIZE * 2);
private static final Map, Boolean> registeredXMLBindingClassList = new ObjectPool<>(POOL_SIZE);
private static final Map, Set> registeredNonPropGetSetMethodPool = new ObjectPool<>(POOL_SIZE);
private static final Map, Map> entityPropFieldPool = new ObjectPool<>(POOL_SIZE);
// ...
private static final Map, List> entityDeclaredPropNameListPool = new ObjectPool<>(POOL_SIZE);
private static final Map, Map> entityDeclaredPropGetMethodPool = new ObjectPool<>(POOL_SIZE);
private static final Map, Map> entityDeclaredPropSetMethodPool = new ObjectPool<>(POOL_SIZE);
private static final Map, Map> entityPropGetMethodPool = new ObjectPool<>(POOL_SIZE);
private static final Map, Map> entityPropSetMethodPool = new ObjectPool<>(POOL_SIZE);
private static final Map, Map>> entityInlinePropGetMethodPool = new ObjectPool<>(POOL_SIZE);
private static final Map, Map>> entityInlinePropSetMethodPool = new ObjectPool<>(POOL_SIZE);
// ...
private static final Map formalizedPropNamePool = new ObjectPool<>(POOL_SIZE * 2);
private static final Map methodPropNamePool = new ObjectPool<>(POOL_SIZE * 2);
private static final Map[]> methodTypeArgumentsPool = new ObjectPool<>(POOL_SIZE * 2);
private static final Map methodParameterizedTypeNamePool = new ObjectPool<>(POOL_SIZE * 2);
// reserved words.
private static final Map keyWordMapper = new HashMap<>(16);
static {
keyWordMapper.put("class", "clazz");
}
private static final Set nonGetMethodName = new HashSet<>(16);
static {
nonGetMethodName.add("getClass");
nonGetMethodName.add("hashCode");
}
private static final Map, Package> packagePool = new ObjectPool<>(POOL_SIZE);
private static final Map, String> packageNamePool = new ObjectPool<>(POOL_SIZE);
private static final Map> clsNamePool = new ObjectPool<>(POOL_SIZE);
private static final Map, String> simpleClassNamePool = new ObjectPool<>(POOL_SIZE);
private static final Map, String> nameClassPool = new ObjectPool<>(POOL_SIZE);
private static final Map, String> canonicalClassNamePool = new ObjectPool<>(POOL_SIZE);
private static final Map, Class>> enclosingClassPool = new ObjectPool<>(POOL_SIZE);
private static final Map, Map[], Constructor>>> classDeclaredConstructorPool = new ObjectPool<>(POOL_SIZE);
private static final Map, Map[], Method>>> classDeclaredMethodPool = new ObjectPool<>(POOL_SIZE);
static final Class> CLASS_MASK = ClassMask.class;
static final Method METHOD_MASK = ClassUtil.internalGetDeclaredMethod(ClassMask.class, "methodMask");
static final Field FIELD_MASK;
static {
try {
FIELD_MASK = ClassMask.class.getDeclaredField(ClassMask.FIELD_MASK);
} catch (Exception e) {
throw N.toRuntimeException(e);
}
}
/**
* The property maybe only has get method if its type is collection or map by xml binding specificatio
* Otherwise, it will be ignored if not registered by calling this method.
*
* @param cls
*/
public static void registerXMLBindingClassForPropGetSetMethod(final Class> cls) {
if (registeredXMLBindingClassList.containsKey(cls)) {
return;
}
synchronized (entityDeclaredPropGetMethodPool) {
registeredXMLBindingClassList.put(cls, false);
if (entityDeclaredPropGetMethodPool.containsKey(cls)) {
entityDeclaredPropGetMethodPool.remove(cls);
entityDeclaredPropSetMethodPool.remove(cls);
entityPropFieldPool.remove(cls);
loadPropGetSetMethodList(cls);
}
}
}
public static void registerNonEntityClass(final Class> cls) {
TypeFactory.registerNonEntityClass(cls);
}
public static void registerNonPropGetSetMethod(final Class> cls, final String propName) {
Set set = registeredNonPropGetSetMethodPool.get(cls);
if (set == null) {
synchronized (registeredNonPropGetSetMethodPool) {
set = registeredNonPropGetSetMethodPool.get(cls);
if (set == null) {
set = new HashSet<>();
registeredNonPropGetSetMethodPool.put(cls, set);
}
}
}
set.add(propName);
}
public static void registerPropGetSetMethod(final String propName, final Method method) {
Class> cls = method.getDeclaringClass();
synchronized (entityDeclaredPropGetMethodPool) {
if (isGetMethod(method)) {
Map propMethodMap = entityPropGetMethodPool.get(cls);
if (propMethodMap == null) {
loadPropGetSetMethodList(cls);
propMethodMap = entityPropGetMethodPool.get(cls);
}
if (propMethodMap.containsKey(propName)) {
if (method.equals(propMethodMap.get(propName)) == false) {
throw new IllegalArgumentException(
propName + " has already been regiestered with different method: " + propMethodMap.get(propName).getName());
}
} else {
propMethodMap.put(propName, method);
}
} else if (method.getName().startsWith(SET)) {
if ((method.getParameterTypes().length != 1)) {
throw new IllegalArgumentException("Invalid set method: " + method.getName());
}
Map propMethodMap = entityPropSetMethodPool.get(cls);
if (propMethodMap == null) {
loadPropGetSetMethodList(cls);
propMethodMap = entityPropSetMethodPool.get(cls);
}
if (propMethodMap.containsKey(propName)) {
if (method.equals(propMethodMap.get(propName)) == false) {
throw new IllegalArgumentException(
propName + " has already been regiestered with different method: " + propMethodMap.get(propName).getName());
}
} else {
propMethodMap.put(propName, method);
}
} else {
throw new IllegalArgumentException("The name of property getter/setter method must start with 'get/is/has' or 'set': " + method.getName());
}
}
}
public static boolean isEntity(final Class> cls) {
Boolean b = entityClassPool.get(cls);
if (b == null) {
final String canonicalClassName = ClassUtil.getCanonicalClassName(cls);
if (N.notNullOrEmpty(canonicalClassName) && (canonicalClassName.startsWith("java.lang.") || canonicalClassName.startsWith("java.util."))) {
b = false;
} else {
b = N.typeOf(cls).isEntity();
}
entityClassPool.put(cls, b);
}
return b;
}
public static boolean isDirtyMarker(final Class> cls) {
Boolean b = dirtyMarkerClassPool.get(cls);
if (b == null) {
b = DirtyMarker.class.isAssignableFrom(cls);
dirtyMarkerClassPool.put(cls, b);
}
return b;
}
/**
* Supports primitive types: boolean, char, byte, short, int, long, float, double. And array type with format {@code java.lang.String[]}
*
* @param clsName
* @return
* @throws IllegalArgumentException if class not found.
*/
@SuppressWarnings("unchecked")
public static Class forClass(final String clsName) throws IllegalArgumentException {
return (Class) forClass(clsName, true);
}
/**
* Supports primitive types: boolean, char, byte, short, int, long, float, double. And array type with format {@code java.lang.String[]}
*
* @param clsName
* @return
* @throws IllegalArgumentException if class not found.
*/
@SuppressWarnings("unchecked")
static Class forClass(final String clsName, final boolean cacheResult) throws IllegalArgumentException {
Class> cls = clsNamePool.get(clsName);
if (cls == null) {
cls = BUILT_IN_TYPE.get(clsName);
if (cls == null) {
try {
cls = Class.forName(clsName);
} catch (ClassNotFoundException e) {
String newClassName = clsName;
if (newClassName.indexOf(WD._PERIOD) < 0) {
int index = newClassName.indexOf("[]");
if (((index < 0) && !SYMBOL_OF_PRIMITIVE_ARRAY_CLASS_NAME.containsKey(newClassName))
|| ((index > 0) && !SYMBOL_OF_PRIMITIVE_ARRAY_CLASS_NAME.containsKey(newClassName.substring(0, index)))) {
newClassName = "java.lang." + newClassName;
try {
cls = Class.forName(newClassName);
BUILT_IN_TYPE.put(clsName, cls);
} catch (ClassNotFoundException e1) {
// ignore.
}
}
}
if (cls == null) {
newClassName = clsName;
int index = newClassName.indexOf("[]");
if (index > 0) {
String componentTypeName = newClassName.substring(0, index);
String temp = newClassName.replaceAll("\\[\\]", "");
if (componentTypeName.equals(temp)) {
int dimensions = (newClassName.length() - temp.length()) / 2;
String prefixOfArray = "";
while (dimensions-- > 0) {
prefixOfArray += "[";
}
String symbolOfPrimitiveArraryClassName = SYMBOL_OF_PRIMITIVE_ARRAY_CLASS_NAME.get(componentTypeName);
if (symbolOfPrimitiveArraryClassName != null) {
try {
cls = Class.forName(prefixOfArray + symbolOfPrimitiveArraryClassName);
BUILT_IN_TYPE.put(clsName, cls);
} catch (ClassNotFoundException e2) {
// ignore.
}
} else {
try {
final Type> componentType = N.typeOf(componentTypeName);
if (componentType.clazz().equals(Object.class) && !componentType.name().equals(ObjectType.OBJECT)) {
throw new IllegalArgumentException("No Class found by name: " + clsName);
}
cls = Class.forName(prefixOfArray + "L" + componentType.clazz().getCanonicalName() + ";");
} catch (ClassNotFoundException e3) {
// ignore.
}
}
}
}
if (cls == null) {
newClassName = clsName;
int lastIndex = -1;
while ((lastIndex = newClassName.lastIndexOf(WD._PERIOD)) > 0) {
newClassName = newClassName.substring(0, lastIndex) + "$" + newClassName.substring(lastIndex + 1);
try {
cls = Class.forName(newClassName);
break;
} catch (ClassNotFoundException e3) {
// ignore.
}
}
}
}
}
}
if (cls == null) {
throw new IllegalArgumentException("No class found by name: " + clsName);
}
if (cacheResult) {
clsNamePool.put(clsName, cls);
}
}
return (Class) cls;
}
// Superclasses/Superinterfaces. Copied from Apache Commons Lang under Apache License v2.
// ----------------------------------------------------------------------
/**
* Copied from Apache Commons Lang under Apache License v2.
*
* Gets a {@code List} of super classes for the given class, excluding {@code Object.class}.
*
* @param cls the class to look up.
* @return the {@code List} of super classes in order going up from this one.
*/
public static List> getAllSuperclasses(final Class> cls) {
final List> classes = new ArrayList<>();
Class> superclass = cls.getSuperclass();
while (superclass != null && !superclass.equals(Object.class)) {
classes.add(superclass);
superclass = superclass.getSuperclass();
}
return classes;
}
/**
* Copied from Apache Commons Lang under Apache License v2.
*
* Gets a {@code List} of all interfaces implemented by the given
* class and its super classes.
*
* The order is determined by looking through each interface in turn as
* declared in the source file and following its hierarchy up. Then each
* superclass is considered in the same way. Later duplicates are ignored,
* so the order is maintained.
*
* @param cls the class to look up.
* @return the {@code List} of interfaces in order
*/
public static Set> getAllInterfaces(final Class> cls) {
final Set> interfacesFound = new LinkedHashSet<>();
getAllInterfaces(cls, interfacesFound);
return interfacesFound;
}
private static void getAllInterfaces(Class> cls, final Set> interfacesFound) {
while (cls != null) {
final Class>[] interfaces = cls.getInterfaces();
for (final Class> i : interfaces) {
if (interfacesFound.add(i)) {
getAllInterfaces(i, interfacesFound);
}
}
cls = cls.getSuperclass();
}
}
/**
* Returns all the interfaces and super classes the specified class implements or extends, excluding {@code Object.class}.
* @param cls
* @return
*/
public static Set> getAllSuperTypes(final Class> cls) {
final Set> superTypesFound = new LinkedHashSet<>();
getAllSuperTypes(cls, superTypesFound);
return superTypesFound;
}
private static void getAllSuperTypes(Class> cls, final Set> superTypesFound) {
while (cls != null) {
final Class>[] interfaces = cls.getInterfaces();
for (final Class> i : interfaces) {
if (superTypesFound.add(i)) {
getAllInterfaces(i, superTypesFound);
}
}
Class> superclass = cls.getSuperclass();
if (superclass != null && !superclass.equals(Object.class) && superTypesFound.add(superclass)) {
getAllSuperTypes(superclass, superTypesFound);
}
cls = cls.getSuperclass();
}
}
public static String getParameterizedTypeNameByMethod(final Method method) {
String parameterizedTypeName = methodParameterizedTypeNamePool.get(method);
if (parameterizedTypeName == null) {
parameterizedTypeName = formatParameterizedTypeName(
(N.isNullOrEmpty(method.getGenericParameterTypes()) ? method.getGenericReturnType() : method.getGenericParameterTypes()[0]).getTypeName());
methodParameterizedTypeNamePool.put(method, parameterizedTypeName);
}
return parameterizedTypeName;
}
static String formatParameterizedTypeName(final String parameterizedTypeName) {
String res = parameterizedTypeName.replaceAll("java.lang.", "").replaceAll("class ", "");
final int idx = res.lastIndexOf('$');
if (idx > 0) {
final StringBuilder sb = new StringBuilder();
for (int len = res.length(), i = len - 1; i >= 0; i--) {
char ch = res.charAt(i);
sb.append(ch);
if (ch == '$') {
int j = i;
char x = 0;
while (--i >= 0 && (Character.isLetterOrDigit(x = res.charAt(i)) || x == '_' || x == '.')) {
}
final String tmp = res.substring(i + 1, j);
if (tmp.substring(0, tmp.length() / 2).equals(tmp.substring(tmp.length() / 2 + 1))) {
sb.append(StringUtil.reverse(tmp.substring(0, tmp.length() / 2)));
} else {
sb.append(StringUtil.reverse(tmp));
}
i++;
}
}
res = sb.reverse().toString();
}
return res;
}
public static Class>[] getTypeArgumentsByMethod(final Method method) {
Class>[] typeParameterClasses = methodTypeArgumentsPool.get(method);
if (typeParameterClasses == null) {
java.lang.reflect.Type genericParameterType = N.isNullOrEmpty(method.getGenericParameterTypes()) ? method.getGenericReturnType()
: method.getGenericParameterTypes()[0];
if (genericParameterType instanceof ParameterizedType) {
ParameterizedType aType = (ParameterizedType) genericParameterType;
java.lang.reflect.Type[] parameterArgTypes = aType.getActualTypeArguments();
typeParameterClasses = new Class[parameterArgTypes.length];
for (int i = 0; i < parameterArgTypes.length; i++) {
if (parameterArgTypes[i] instanceof Class) {
typeParameterClasses[i] = (Class>) parameterArgTypes[i];
} else if (parameterArgTypes[i] instanceof ParameterizedType && ((ParameterizedType) parameterArgTypes[i]).getRawType() instanceof Class) {
typeParameterClasses[i] = (Class>) ((ParameterizedType) parameterArgTypes[i]).getRawType();
} else {
typeParameterClasses = new Class>[0];
break;
}
}
} else {
typeParameterClasses = new Class>[0];
}
methodTypeArgumentsPool.put(method, typeParameterClasses);
}
return typeParameterClasses.length == 0 ? typeParameterClasses : typeParameterClasses.clone();
}
/**
*
* @param cls
* @return null
if it's primitive type or no package defined for the class.
*/
public static Package getPackage(final Class> cls) {
Package pkg = packagePool.get(cls);
if (pkg == null) {
if (Primitives.isPrimitiveType(cls)) {
return null;
}
pkg = cls.getPackage();
if (pkg != null) {
packagePool.put(cls, pkg);
}
}
return pkg;
}
/**
*
* @param cls
* @return null
if it's primitive type or no package defined for the class.
*/
public static String getPackageName(final Class> cls) {
String pkgName = packageNamePool.get(cls);
if (pkgName == null) {
Package pkg = ClassUtil.getPackage(cls);
pkgName = pkg == null ? "" : pkg.getName();
packageNamePool.put(cls, pkgName);
}
return pkgName;
}
// private static Class[] getTypeArguments(Class cls) {
// java.lang.reflect.Type[] typeArgs = null;
// java.lang.reflect.Type[] genericInterfaces = cls.getGenericInterfaces();
//
// if (notNullOrEmpty(genericInterfaces)) {
// for (java.lang.reflect.Type type : genericInterfaces) {
// typeArgs = ((ParameterizedType) type).getActualTypeArguments();
//
// if (notNullOrEmpty(typeArgs)) {
// break;
// }
// }
// } else {
// java.lang.reflect.Type genericSuperclass = cls.getGenericSuperclass();
//
// if (genericSuperclass != null) {
// typeArgs = ((ParameterizedType) genericSuperclass).getActualTypeArguments();
// }
// }
//
// if (notNullOrEmpty(typeArgs)) {
// Class[] clses = new Class[typeArgs.length];
//
// for (int i = 0; i < typeArgs.length; i++) {
// clses[i] = (Class) typeArgs[i];
// }
//
// return clses;
// } else {
// return null;
// }
// }
// /**
// * Returns the method declared in the specified {@code cls} with the specified method name.
// *
// * @param cls
// * @param methodName is case insensitive
// * @return {@code null} if no method is found by specified name
// */
// public static Method findDeclaredMethodByName(Class> cls, String methodName) {
// Method method = null;
//
// Method[] methods = cls.getDeclaredMethods();
//
// for (Method m : methods) {
// if (m.getName().equalsIgnoreCase(methodName)) {
// if ((method == null) || Modifier.isPublic(m.getModifiers())
// || (Modifier.isProtected(m.getModifiers()) && (!Modifier.isProtected(method.getModifiers())))
// || (!Modifier.isPrivate(m.getModifiers()) && Modifier.isPrivate(method.getModifiers()))) {
//
// method = m;
// }
//
// if (Modifier.isPublic(method.getModifiers())) {
// break;
// }
// }
// }
//
// // SHOULD NOT set it true here.
// // if (method != null) {
// // method.setAccessible(true);
// // }
//
// return method;
// }
public static List> getClassesByPackage(String pkgName, boolean isRecursive, boolean skipClassLoaddingException) throws UncheckedIOException {
return getClassesByPackage(pkgName, isRecursive, skipClassLoaddingException, Fn.alwaysTrue());
}
public static List> getClassesByPackage(String pkgName, boolean isRecursive, boolean skipClassLoaddingException,
Try.Predicate super Class>, E> predicate) throws UncheckedIOException, E {
if (logger.isInfoEnabled()) {
logger.info("Looking for classes in package: " + pkgName);
}
String pkgPath = packageName2FilePath(pkgName);
List resourceList = getResources(pkgName);
if (N.isNullOrEmpty(resourceList)) {
throw new IllegalArgumentException("No resource found by package " + pkgName);
}
List> classes = new ArrayList>();
for (URL resource : resourceList) {
// Get a File object for the package
String fullPath = resource.getPath().replace("%20", " ").replaceFirst("[.]jar[!].*", JAR_POSTFIX).replaceFirst("file:", "");
if (logger.isInfoEnabled()) {
logger.info("ClassDiscovery: FullPath = " + fullPath);
}
File file = new File(fullPath);
if (file.exists() && file.isDirectory()) {
// Get the list of the files contained in the package
File[] files = file.listFiles();
if (N.isNullOrEmpty(files)) {
continue;
}
for (int i = 0; i < files.length; i++) {
if (files[i] == null) {
continue;
}
// we are only interested in .class files
if (files[i].isFile() && files[i].getName().endsWith(CLASS_POSTFIX)) {
// removes the .class extension
String className = pkgName + '.' + files[i].getName().substring(0, files[i].getName().length() - CLASS_POSTFIX.length());
try {
Class> clazz = ClassUtil.forClass(className, false);
if (clazz.getCanonicalName() != null && predicate.test(clazz)) {
classes.add(clazz);
}
} catch (Throwable e) {
if (logger.isWarnEnabled()) {
logger.warn("ClassNotFoundException loading " + className);
}
if (!skipClassLoaddingException) {
throw new RuntimeException("ClassNotFoundException loading " + className);
}
}
} else if (files[i].isDirectory() && isRecursive) {
String subPkgName = pkgName + WD._PERIOD + files[i].getName();
classes.addAll(getClassesByPackage(subPkgName, isRecursive, skipClassLoaddingException, predicate));
}
}
} else if (file.exists() && file.getName().endsWith(JAR_POSTFIX)) {
JarFile jarFile = null;
try {
jarFile = new JarFile(file.getPath());
Enumeration entries = jarFile.entries();
JarEntry entry = null;
String entryName = null;
while (entries.hasMoreElements()) {
entry = entries.nextElement();
entryName = entry.getName();
if (entryName.startsWith(pkgPath)) {
if (entryName.endsWith(CLASS_POSTFIX) && (entryName.indexOf("/", pkgPath.length()) < 0)) {
String className = filePath2PackageName(entryName).replace(CLASS_POSTFIX, "");
try {
Class> clazz = ClassUtil.forClass(className, false);
if ((clazz.getCanonicalName() != null) && (clazz.getPackage().getName().equals(pkgName)
|| (clazz.getPackage().getName().startsWith(pkgName) && isRecursive)) && predicate.test(clazz)) {
classes.add(clazz);
}
} catch (Throwable e) {
if (logger.isWarnEnabled()) {
logger.warn("ClassNotFoundException loading " + className);
}
if (!skipClassLoaddingException) {
IOUtil.close(jarFile);
jarFile = null;
throw new RuntimeException("ClassNotFoundException loading " + className);
}
}
} else if (entry.isDirectory() && (entryName.length() > (pkgPath.length() + 1)) && isRecursive) {
String subPkgName = filePath2PackageName(entryName);
classes.addAll(getClassesByPackage(subPkgName, isRecursive, skipClassLoaddingException, predicate));
}
}
}
} catch (IOException e) {
throw new UncheckedIOException(pkgName + " (" + file + ") does not appear to be a valid package", e);
} finally {
IOUtil.close(jarFile);
}
}
}
return classes;
}
private static String packageName2FilePath(String pkgName) {
String pkgPath = pkgName.replace('.', '/');
pkgPath = pkgPath.endsWith("/") ? pkgPath : (pkgPath + "/");
return pkgPath;
}
private static List getResources(String pkgName) {
List resourceList = new ArrayList<>();
String pkgPath = packageName2FilePath(pkgName);
ClassLoader localClassLoader = ClassUtil.class.getClassLoader();
ClassLoader sysClassLoader = ClassLoader.getSystemClassLoader();
try {
Enumeration resources = localClassLoader.getResources(pkgPath);
while (resources != null && resources.hasMoreElements()) {
resourceList.add(resources.nextElement());
}
if (N.isNullOrEmpty(resourceList)) {
resources = sysClassLoader.getResources(pkgPath);
while (resources != null && resources.hasMoreElements()) {
resourceList.add(resources.nextElement());
}
}
if (N.isNullOrEmpty(resourceList)) {
resources = localClassLoader.getResources(pkgName);
while (resources != null && resources.hasMoreElements()) {
resourceList.add(resources.nextElement());
}
}
if (N.isNullOrEmpty(resourceList)) {
resources = sysClassLoader.getResources(pkgName);
while (resources != null && resources.hasMoreElements()) {
resourceList.add(resources.nextElement());
}
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
if (logger.isInfoEnabled()) {
logger.info("Found resources: " + resourceList + " by package name(" + pkgName + ")");
}
return resourceList;
}
private static String filePath2PackageName(String entryName) {
String pkgName = entryName.replace('/', '.').replace('\\', '.');
pkgName = pkgName.endsWith(".") ? pkgName.substring(0, pkgName.length() - 1) : pkgName;
return pkgName;
}
public static String getClassName(final Class> cls) {
String clsName = nameClassPool.get(cls);
if (clsName == null) {
clsName = cls.getName();
nameClassPool.put(cls, clsName);
}
return clsName;
}
public static String getSimpleClassName(final Class> cls) {
String clsName = simpleClassNamePool.get(cls);
if (clsName == null) {
clsName = cls.getSimpleName();
simpleClassNamePool.put(cls, clsName);
}
return clsName;
}
public static String getCanonicalClassName(final Class> cls) {
String clsName = canonicalClassNamePool.get(cls);
if (clsName == null) {
clsName = cls.getCanonicalName();
if (clsName != null) {
canonicalClassNamePool.put(cls, clsName);
}
}
return clsName;
}
public static Class> getEnclosingClass(final Class> cls) {
Class> enclosingClass = enclosingClassPool.get(cls);
if (enclosingClass == null) {
enclosingClass = cls.getEnclosingClass();
if (enclosingClass == null) {
enclosingClass = CLASS_MASK;
}
enclosingClassPool.put(cls, enclosingClass);
}
return (enclosingClass == CLASS_MASK) ? null : enclosingClass;
}
/**
* Returns the constructor declared in the specified {@code cls} with the specified {@code parameterTypes}.
*
* @param cls
* @param parameterTypes
* @return {@code null} if no constructor is found
*/
@SafeVarargs
public static Constructor getDeclaredConstructor(final Class cls, final Class>... parameterTypes) {
Map[], Constructor>> constructorPool = classDeclaredConstructorPool.get(cls);
Constructor constructor = null;
if (constructorPool != null) {
constructor = (Constructor) constructorPool.get(parameterTypes);
}
if (constructor == null) {
try {
constructor = cls.getDeclaredConstructor(parameterTypes);
// SHOULD NOT set it true here.
// constructor.setAccessible(true);
} catch (NoSuchMethodException e) {
// ignore.
}
if (constructor != null) {
if (constructorPool == null) {
constructorPool = new ArrayHashMap<>(ConcurrentHashMap.class);
classDeclaredConstructorPool.put(cls, constructorPool);
}
constructorPool.put(parameterTypes.clone(), constructor);
}
}
return constructor;
}
/**
* Returns the method declared in the specified {@code cls} with the specified {@code methodName} and {@code parameterTypes}.
*
* @param cls
* @param methodName
* @param parameterTypes
* @return {@code null} if no method is found
*/
@SafeVarargs
public static Method getDeclaredMethod(final Class> cls, final String methodName, final Class>... parameterTypes) {
Map[], Method>> methodNamePool = classDeclaredMethodPool.get(cls);
Map[], Method> methodPool = methodNamePool == null ? null : methodNamePool.get(methodName);
Method method = null;
if (methodPool != null) {
method = methodPool.get(parameterTypes);
}
if (method == null) {
method = internalGetDeclaredMethod(cls, methodName, parameterTypes);
// SHOULD NOT set it true here.
// if (method != null) {
// method.setAccessible(true);
// }
if (method != null) {
if (methodNamePool == null) {
methodNamePool = new ConcurrentHashMap<>();
classDeclaredMethodPool.put(cls, methodNamePool);
}
if (methodPool == null) {
methodPool = new ArrayHashMap<>(ConcurrentHashMap.class);
methodNamePool.put(methodName, methodPool);
}
methodPool.put(parameterTypes.clone(), method);
}
}
return method;
}
static Method internalGetDeclaredMethod(final Class> cls, final String methodName, final Class>... parameterTypes) {
Method method = null;
try {
method = cls.getDeclaredMethod(methodName, parameterTypes);
} catch (NoSuchMethodException e) {
// ignore.
}
if (method == null) {
Method[] methods = cls.getDeclaredMethods();
for (Method m : methods) {
if (m.getName().equalsIgnoreCase(methodName) && N.equals(parameterTypes, m.getParameterTypes())) {
method = m;
break;
}
}
}
return method;
}
@SafeVarargs
public static T invokeConstructor(final Constructor constructor, final Object... args) {
try {
return constructor.newInstance(args);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw N.toRuntimeException(e);
}
}
@SuppressWarnings("unchecked")
@SafeVarargs
public static T invokeMethod(final Method method, final Object... args) {
return invokeMethod(null, method, args);
}
@SuppressWarnings("unchecked")
@SafeVarargs
public static T invokeMethod(final Object instance, final Method method, final Object... args) {
try {
return (T) method.invoke(instance, args);
} catch (IllegalAccessException | InvocationTargetException e) {
throw N.toRuntimeException(e);
}
}
/**
* Returns an immutable entity property name List by the specified class.
*
* @param cls
* @return
*/
public static List getPropNameList(final Class> cls) {
List propNameList = entityDeclaredPropNameListPool.get(cls);
if (propNameList == null) {
loadPropGetSetMethodList(cls);
propNameList = entityDeclaredPropNameListPool.get(cls);
}
return propNameList;
}
/**
*
* @param cls
* @param propNameToExcluded
* @return
*/
public static List getPropNameListExclusively(final Class> cls, final Set propNameToExcluded) {
final List propNameList = getPropNameList(cls);
if (N.isNullOrEmpty(propNameToExcluded)) {
return new ArrayList<>(propNameList);
} else {
final List res = new ArrayList<>(propNameList.size() - propNameToExcluded.size());
for (String propName : propNameList) {
if (!propNameToExcluded.contains(propName)) {
res.add(propName);
}
}
return res;
}
}
@SuppressWarnings("rawtypes")
public static List getPropNameListExclusively(final Class> cls, final Collection propNameToExcluded) {
if (N.isNullOrEmpty(propNameToExcluded)) {
return new ArrayList<>(getPropNameList(cls));
} else if (propNameToExcluded instanceof Set) {
return getPropNameListExclusively(cls, (Set) propNameToExcluded);
} else {
return getPropNameListExclusively(cls, new HashSet<>(propNameToExcluded));
}
}
/**
* Call registerXMLBindingClassForPropGetSetMethod first to retrieve the property
* getter/setter method for the class/bean generated/wrote by JAXB
* specificatio
*
* @param cls
* @return
*/
public static Map getPropGetMethodList(final Class> cls) {
Map getterMethodList = entityDeclaredPropGetMethodPool.get(cls);
if (getterMethodList == null) {
loadPropGetSetMethodList(cls);
getterMethodList = entityDeclaredPropGetMethodPool.get(cls);
}
return getterMethodList;
}
public static Map getPropSetMethodList(final Class> cls) {
Map setterMethodList = entityDeclaredPropSetMethodPool.get(cls);
if (setterMethodList == null) {
loadPropGetSetMethodList(cls);
setterMethodList = entityDeclaredPropSetMethodPool.get(cls);
}
return setterMethodList;
}
private static void loadPropGetSetMethodList(final Class> cls) {
synchronized (entityDeclaredPropGetMethodPool) {
if (entityDeclaredPropGetMethodPool.containsKey(cls)) {
return;
}
Object instance = null;
if (registeredXMLBindingClassList.containsKey(cls)) {
try {
instance = cls.newInstance();
} catch (Exception e) {
if (logger.isWarnEnabled()) {
logger.warn("Failed to new instance of class: " + cls.getCanonicalName() + " to check setter method by getter method");
}
}
registeredXMLBindingClassList.put(cls, true);
}
Map propFieldMap = new LinkedHashMap<>();
Map propGetMethodMap = new LinkedHashMap<>();
Map propSetMethodMap = new LinkedHashMap<>();
List> allClasses = new ArrayList<>();
allClasses.add(cls);
while (allClasses.get(allClasses.size() - 1).getSuperclass() != null) {
allClasses.add(allClasses.get(allClasses.size() - 1).getSuperclass());
}
Class> clazz = null;
Method setMethod = null;
for (int i = allClasses.size() - 1; i >= 0; i--) {
clazz = allClasses.get(i);
if (java.util.Date.class.isAssignableFrom(clazz) || Calendar.class.equals(clazz)) {
continue;
}
Map statisFinalFields = getPublicStaticStringFields(clazz);
String propName = null;
// sort the methods by the order of declared fields
for (Field field : clazz.getDeclaredFields()) {
for (Method method : clazz.getMethods()) {
if (isFieldGetMethod(method, field)) {
propName = getPropNameByMethod(method);
propName = (statisFinalFields.get(propName) != null) ? statisFinalFields.get(propName) : propName;
if (propGetMethodMap.containsKey(propName)) {
break;
}
setMethod = getSetMethod(clazz, propName, method);
if (setMethod != null) {
field.setAccessible(true);
propFieldMap.put(propName, field);
propGetMethodMap.put(propName, method);
propSetMethodMap.put(propName, setMethod);
break;
}
if (isJAXBGetMethod(instance, method)) {
field.setAccessible(true);
propFieldMap.put(propName, field);
propGetMethodMap.put(propName, method);
break;
}
}
}
}
for (Method method : clazz.getMethods()) {
if (isGetMethod(method)) {
propName = getPropNameByMethod(method);
propName = (statisFinalFields.get(propName) != null) ? statisFinalFields.get(propName) : propName;
if (propGetMethodMap.containsKey(propName)) {
continue;
}
setMethod = getSetMethod(clazz, propName, method);
if (setMethod != null) {
propGetMethodMap.put(propName, method);
propSetMethodMap.put(propName, setMethod);
continue;
}
if (isJAXBGetMethod(instance, method)) {
propGetMethodMap.put(propName, method);
continue;
}
}
}
}
for (Class> key : registeredNonPropGetSetMethodPool.keySet()) {
if (key.isAssignableFrom(cls)) {
final Set set = registeredNonPropGetSetMethodPool.get(key);
for (String nonPropName : set) {
for (String propName : propGetMethodMap.keySet()) {
if (propName.equalsIgnoreCase(nonPropName)) {
propGetMethodMap.remove(propName);
propSetMethodMap.remove(propName);
propFieldMap.remove(propName);
break;
}
}
}
}
}
// for Double-Checked Locking is Broke initialize it before
// put it into map.
Map tempFieldMap = new ObjectPool<>(64);
tempFieldMap.putAll(propFieldMap);
tempFieldMap.keySet();
entityPropFieldPool.put(cls, tempFieldMap);
Map unmodifiableMethodMap = Collections.unmodifiableMap(propGetMethodMap);
unmodifiableMethodMap.keySet();
entityDeclaredPropGetMethodPool.put(cls, unmodifiableMethodMap);
if (entityPropGetMethodPool.get(cls) == null) {
Map tmp = new ObjectPool<>(64);
tmp.putAll(propGetMethodMap);
entityPropGetMethodPool.put(cls, tmp);
} else {
entityPropGetMethodPool.get(cls).putAll(propGetMethodMap);
}
// for Double-Checked Locking is Broke initialize it before
// put it into map.
unmodifiableMethodMap = Collections.unmodifiableMap(propSetMethodMap);
unmodifiableMethodMap.keySet();
entityDeclaredPropSetMethodPool.put(cls, unmodifiableMethodMap);
if (entityPropSetMethodPool.get(cls) == null) {
Map tmp = new ObjectPool<>(64);
tmp.putAll(propSetMethodMap);
entityPropSetMethodPool.put(cls, tmp);
} else {
entityPropSetMethodPool.get(cls).putAll(propSetMethodMap);
}
entityDeclaredPropNameListPool.put(cls, ImmutableList.copyOf(propSetMethodMap.keySet()));
}
}
private static boolean isGetMethod(final Method method) {
String mn = method.getName();
return (mn.startsWith(GET) || mn.startsWith(IS) || mn.startsWith(HAS)) && (N.isNullOrEmpty(method.getParameterTypes()))
&& !void.class.equals(method.getReturnType()) && !nonGetMethodName.contains(mn);
}
static boolean isFieldGetMethod(final Method method, final Field field) {
if (!isGetMethod(method)) {
return false;
}
if (!method.getReturnType().isAssignableFrom(field.getType())) {
return false;
}
String fieldName = field.getName();
String methodName = method.getName();
return (methodName.startsWith(IS) && (methodName.equalsIgnoreCase(fieldName) || methodName.substring(2).equalsIgnoreCase(fieldName)))
|| (methodName.startsWith(HAS) && (methodName.equalsIgnoreCase(fieldName) || methodName.substring(3).equalsIgnoreCase(fieldName)))
|| (methodName.startsWith(GET) && methodName.substring(3).equalsIgnoreCase(fieldName));
}
static boolean isJAXBGetMethod(final Object instance, final Method method) {
try {
return (instance != null) && (Collection.class.isAssignableFrom(method.getReturnType()) || Map.class.isAssignableFrom(method.getReturnType()))
&& (invokeMethod(instance, method) != null);
} catch (Exception e) {
return false;
}
}
private static Method getSetMethod(final Class> clazz, final String propName, final Method getMethod) {
Method setMethod = internalGetDeclaredMethod(clazz, SET + propName, getMethod.getReturnType());
return ((setMethod != null) && (void.class.equals(setMethod.getReturnType()) || setMethod.getDeclaringClass().equals(setMethod.getReturnType())))
? setMethod : null;
}
private static Map getPublicStaticStringFields(final Class cls) {
Map statisFinalFields = new HashMap<>();
for (Field field : cls.getFields()) {
if (Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers())
&& String.class.equals(field.getType())) {
String value;
try {
value = (String) field.get(null);
statisFinalFields.put(value, value);
} catch (Exception e) {
// ignore. should not happe
}
}
}
return statisFinalFields;
}
/**
* Returns the property get method declared in the specified {@code cls}
* with the specified property name {@code propName}.
* {@code null} is returned if no method is found.
*
* Call registerXMLBindingClassForPropGetSetMethod first to retrieve the property
* getter/setter method for the class/bean generated/wrote by JAXB
* specificatio
*
* @param cls
* @param propName
* @return
*/
public static Method getPropGetMethod(final Class> cls, final String propName) {
Map propGetMethodMap = entityPropGetMethodPool.get(cls);
if (propGetMethodMap == null) {
loadPropGetSetMethodList(cls);
propGetMethodMap = entityPropGetMethodPool.get(cls);
}
Method method = propGetMethodMap.get(propName);
if (method == null) {
synchronized (entityDeclaredPropGetMethodPool) {
Map getterMethodList = getPropGetMethodList(cls);
for (String key : getterMethodList.keySet()) {
if (isPropName(cls, propName, key)) {
method = getterMethodList.get(key);
break;
}
}
if ((method == null) && !propName.equalsIgnoreCase(formalizePropName(propName))) {
method = getPropGetMethod(cls, formalizePropName(propName));
}
// set method mask to avoid query next time.
if (method == null) {
method = METHOD_MASK;
}
propGetMethodMap.put(propName, method);
}
}
return (method == METHOD_MASK) ? null : method;
}
static boolean isPropName(final Class> cls, String inputPropName, final String propNameByMethod) {
if (inputPropName.length() > 128) {
throw new IllegalArgumentException("The property name execeed 128: " + inputPropName);
}
inputPropName = inputPropName.trim();
return inputPropName.equalsIgnoreCase(propNameByMethod) || inputPropName.replace(WD.UNDERSCORE, N.EMPTY_STRING).equalsIgnoreCase(propNameByMethod)
|| inputPropName.equalsIgnoreCase(getSimpleClassName(cls) + WD._PERIOD + propNameByMethod)
|| (inputPropName.startsWith(GET) && inputPropName.substring(3).equalsIgnoreCase(propNameByMethod))
|| (inputPropName.startsWith(SET) && inputPropName.substring(3).equalsIgnoreCase(propNameByMethod))
|| (inputPropName.startsWith(IS) && inputPropName.substring(2).equalsIgnoreCase(propNameByMethod))
|| (inputPropName.startsWith(HAS) && inputPropName.substring(3).equalsIgnoreCase(propNameByMethod));
}
/**
* Returns the property set method declared in the specified {@code cls}
* with the specified property name {@code propName}.
* {@code null} is returned if no method is found.
*
* @param cls
* @param propName
* @return
*/
public static Method getPropSetMethod(final Class> cls, final String propName) {
Map propSetMethodMap = entityPropSetMethodPool.get(cls);
if (propSetMethodMap == null) {
loadPropGetSetMethodList(cls);
propSetMethodMap = entityPropSetMethodPool.get(cls);
}
Method method = propSetMethodMap.get(propName);
if (method == null) {
synchronized (entityDeclaredPropGetMethodPool) {
Map setterMethodList = getPropSetMethodList(cls);
for (String key : setterMethodList.keySet()) {
if (isPropName(cls, propName, key)) {
method = propSetMethodMap.get(key);
break;
}
}
if ((method == null) && !propName.equalsIgnoreCase(formalizePropName(propName))) {
method = getPropSetMethod(cls, formalizePropName(propName));
}
// set method mask to avoid query next time.
if (method == null) {
method = METHOD_MASK;
}
propSetMethodMap.put(propName, method);
}
}
return (method == METHOD_MASK) ? null : method;
}
public static Field getPropField(final Class> cls, final String propName) {
Map propFieldMap = entityPropFieldPool.get(cls);
if (propFieldMap == null) {
loadPropGetSetMethodList(cls);
propFieldMap = entityPropFieldPool.get(cls);
}
Field field = propFieldMap.get(propName);
if (field == null) {
synchronized (entityDeclaredPropGetMethodPool) {
Map getterMethodList = ClassUtil.checkPropGetMethodList(cls);
for (String key : getterMethodList.keySet()) {
if (isPropName(cls, propName, key)) {
field = propFieldMap.get(key);
break;
}
}
if ((field == null) && !propName.equalsIgnoreCase(formalizePropName(propName))) {
field = getPropField(cls, formalizePropName(propName));
}
// set method mask to avoid query next time.
if (field == null) {
field = FIELD_MASK;
}
propFieldMap.put(propName, field);
}
}
return (field == FIELD_MASK) ? null : field;
}
/**
* Return the specified {@code propValue} got by the specified method
* {@code propSetMethod} in the specified {@code entity}.
*
* @param entity
* MapEntity is not supported
* @param propGetMethod
*
* @return
*/
@SuppressWarnings("unchecked")
public static T getPropValue(final Object entity, final Method propGetMethod) {
try {
return (T) propGetMethod.invoke(entity);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw N.toRuntimeException(e);
}
}
/**
* Set the specified {@code propValue} to {@code entity} by the specified
* method {@code propSetMethod}. This method will try to convert
* {@code propValue} to appropriate type and set again if fails to set in
* the first time. The final value which is set to the property will be
* returned if property is set successfully finally. it could be the input
* {@code propValue} or converted property value, otherwise, exception will
* be threw if the property value is set unsuccessfully.
*
* @param entity
* MapEntity is not supported
* @param propSetMethod
* @param propValue
*/
public static void setPropValue(final Object entity, final Method propSetMethod, Object propValue) {
try {
propSetMethod.invoke(entity, propValue == null ? N.defaultValueOf(propSetMethod.getParameterTypes()[0]) : propValue);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
propValue = N.convert(propValue, ParserUtil.getEntityInfo(entity.getClass()).getPropInfo(propSetMethod.getName()).type);
try {
propSetMethod.invoke(entity, propValue);
} catch (IllegalAccessException | InvocationTargetException e2) {
throw N.toRuntimeException(e);
}
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void setPropValueByGet(final Object entity, final Method propGetMethod, final Object propValue) {
if (propValue == null) {
return;
}
final Object rt = invokeMethod(entity, propGetMethod);
if (rt instanceof Collection) {
((Collection>) rt).addAll((Collection) propValue);
} else if (rt instanceof Map) {
((Map, ?>) rt).putAll((Map) propValue);
} else {
throw new IllegalArgumentException("Failed to set property value by getter method '" + propGetMethod.getName() + "'");
}
}
/**
* Refer to getPropValue(Method, Object)
*
* @param entity
* @param propName
* is case insensitive
* @return {@link #getPropValue(Object, Method)}
*/
@SuppressWarnings("unchecked")
public static T getPropValue(final Object entity, final String propName) {
return getPropValue(entity, propName, false);
}
/**
*
* @param entity
* @param propName
* @param ignoreUnknownProperty
* @return the property value or null if the property doesn't belong to specified entity.
* @throws IllegalArgumentException if the specified property can't be gotten and ignoreUnknownProperty is false.
*/
public static T getPropValue(final Object entity, final String propName, final boolean ignoreUnknownProperty) {
Method getMethod = getPropGetMethod(entity.getClass(), propName);
if (getMethod == null) {
Class> cls = entity.getClass();
Map> inlinePropGetMethodMap = entityInlinePropGetMethodPool.get(cls);
List inlinePropGetMethodQueue = null;
if (inlinePropGetMethodMap == null) {
inlinePropGetMethodMap = new ObjectPool<>(ClassUtil.getPropGetMethodList(cls).size());
entityInlinePropGetMethodPool.put(cls, inlinePropGetMethodMap);
} else {
inlinePropGetMethodQueue = inlinePropGetMethodMap.get(propName);
}
if (inlinePropGetMethodQueue == null) {
inlinePropGetMethodQueue = new ArrayList<>();
final String[] strs = Splitter.with(PROP_NAME_SEPARATOR).splitToArray(propName);
if (strs.length > 1) {
Class> targetClass = cls;
for (String str : strs) {
Method method = getPropGetMethod(targetClass, str);
if (method == null) {
inlinePropGetMethodQueue.clear();
break;
}
inlinePropGetMethodQueue.add(method);
targetClass = method.getReturnType();
}
}
inlinePropGetMethodMap.put(propName, inlinePropGetMethodQueue);
}
if (inlinePropGetMethodQueue.size() == 0) {
if (ignoreUnknownProperty) {
return null;
} else {
throw new IllegalArgumentException(
"No property method found with property name: " + propName + " in class " + ClassUtil.getCanonicalClassName(cls));
}
} else {
Object propEntity = entity;
for (int i = 0, len = inlinePropGetMethodQueue.size(); i < len; i++) {
propEntity = ClassUtil.getPropValue(propEntity, inlinePropGetMethodQueue.get(i));
if (propEntity == null) {
return (T) N.defaultValueOf(inlinePropGetMethodQueue.get(len - 1).getReturnType());
}
}
return (T) propEntity;
}
} else {
return getPropValue(entity, getMethod);
}
}
/**
* Refer to setPropValue(Method, Object, Object).
*
* @param entity
* @param propName
* is case insensitive
* @param propValue
*/
public static void setPropValue(final Object entity, final String propName, final Object propValue) {
setPropValue(entity, propName, propValue, false);
}
/**
*
* @param entity
* @param propName
* @param propValue
* @param ignoreUnknownProperty
* @return true if the property value has been set.
* @throws IllegalArgumentException if the specified property can't be set and ignoreUnknownProperty is false.
*/
public static boolean setPropValue(final Object entity, final String propName, final Object propValue, final boolean ignoreUnknownProperty) {
Method setMethod = getPropSetMethod(entity.getClass(), propName);
if (setMethod == null) {
final Class> cls = entity.getClass();
Method getMethod = getPropGetMethod(cls, propName);
if (getMethod == null) {
Map> inlinePropSetMethodMap = entityInlinePropSetMethodPool.get(cls);
List inlinePropSetMethodQueue = null;
if (inlinePropSetMethodMap == null) {
inlinePropSetMethodMap = new ObjectPool<>(ClassUtil.getPropGetMethodList(cls).size());
entityInlinePropSetMethodPool.put(cls, inlinePropSetMethodMap);
} else {
inlinePropSetMethodQueue = inlinePropSetMethodMap.get(propName);
}
if (inlinePropSetMethodQueue == null) {
inlinePropSetMethodQueue = new ArrayList<>();
final String[] strs = Splitter.with(PROP_NAME_SEPARATOR).splitToArray(propName);
if (strs.length > 1) {
Class> propClass = cls;
for (int i = 0, len = strs.length; i < len; i++) {
if (i == (len - 1)) {
setMethod = getPropSetMethod(propClass, strs[i]);
if (setMethod == null) {
getMethod = getPropGetMethod(propClass, strs[i]);
if (getMethod == null) {
inlinePropSetMethodQueue.clear();
break;
}
inlinePropSetMethodQueue.add(getMethod);
} else {
inlinePropSetMethodQueue.add(setMethod);
}
} else {
getMethod = getPropGetMethod(propClass, strs[i]);
if (getMethod == null) {
inlinePropSetMethodQueue.clear();
break;
}
inlinePropSetMethodQueue.add(getMethod);
propClass = getMethod.getReturnType();
}
}
}
inlinePropSetMethodMap.put(propName, N.isNullOrEmpty(inlinePropSetMethodQueue) ? N. emptyList() : inlinePropSetMethodQueue);
}
if (inlinePropSetMethodQueue.size() == 0) {
if (ignoreUnknownProperty) {
return false;
} else {
throw new IllegalArgumentException("No property method found with property name: " + propName + " in class " + cls.getCanonicalName());
}
} else {
Object propEntity = entity;
Method method = null;
for (int i = 0, len = inlinePropSetMethodQueue.size(); i < len; i++) {
method = inlinePropSetMethodQueue.get(i);
if (i == (len - 1)) {
if (N.isNullOrEmpty(method.getParameterTypes())) {
setPropValueByGet(propEntity, method, propValue);
} else {
setPropValue(propEntity, method, propValue);
}
} else {
Object tmp = ClassUtil.getPropValue(propEntity, method);
if (tmp == null) {
tmp = N.newInstance(method.getReturnType());
ClassUtil.setPropValue(propEntity, ClassUtil.getPropNameByMethod(method), tmp);
}
propEntity = tmp;
}
}
}
} else {
setPropValueByGet(entity, getMethod, propValue);
}
} else {
setPropValue(entity, setMethod, propValue);
}
return true;
}
public static String getPropNameByMethod(final Method getSetMethod) {
String propName = methodPropNamePool.get(getSetMethod);
if (propName == null) {
String methodName = getSetMethod.getName();
propName = formalizePropName(methodName.startsWith(IS) ? methodName.substring(2) : methodName.substring(3));
methodPropNamePool.put(getSetMethod, propName);
}
return propName;
}
/**
* It's designed for field/method/class/column/table names. and source and target Strings will be cached.
*
* @param propName
* @return
*/
public static String formalizePropName(final String propName) {
String newPropName = formalizedPropNamePool.get(propName);
if (newPropName == null) {
newPropName = toCamelCase(propName);
for (String keyWord : keyWordMapper.keySet()) {
if (keyWord.equalsIgnoreCase(newPropName)) {
newPropName = keyWordMapper.get(keyWord);
break;
}
}
formalizedPropNamePool.put(propName, newPropName);
}
return newPropName;
}
/**
* It's designed for field/method/class/column/table names. and source and target Strings will be cached.
*
* @param str
* @return
*/
public static String toCamelCase(final String propName) {
String newPropName = camelCasePropNamePool.get(propName);
if (newPropName == null) {
newPropName = StringUtil.toCamelCase(propName);
newPropName = NameUtil.getCachedName(newPropName);
camelCasePropNamePool.put(propName, newPropName);
}
return newPropName;
}
public static void toCamelCase(final Map props) {
final Map tmp = Objectory.createLinkedHashMap();
for (Map.Entry entry : props.entrySet()) {
tmp.put(ClassUtil.toCamelCase(entry.getKey()), entry.getValue());
}
props.clear();
props.putAll(tmp);
Objectory.recycle(tmp);
}
/**
* It's designed for field/method/class/column/table names. and source and target Strings will be cached.
*
* @param str
* @return
*/
public static String toLowerCaseWithUnderscore(final String str) {
if (N.isNullOrEmpty(str)) {
return str;
}
String result = lowerCaseWithUnderscorePropNamePool.get(str);
if (result == null) {
result = StringUtil.toLowerCaseWithUnderscore(str);
lowerCaseWithUnderscorePropNamePool.put(str, result);
}
return result;
}
public static void toLowerCaseKeyWithUnderscore(final Map props) {
final Map tmp = Objectory.createLinkedHashMap();
for (Map.Entry entry : props.entrySet()) {
tmp.put(ClassUtil.toLowerCaseWithUnderscore(entry.getKey()), entry.getValue());
}
props.clear();
props.putAll(tmp);
Objectory.recycle(tmp);
}
/**
* It's designed for field/method/class/column/table names. and source and target Strings will be cached.
*
* @param str
* @return
*/
public static String toUpperCaseWithUnderscore(final String str) {
if (N.isNullOrEmpty(str)) {
return str;
}
String result = upperCaseWithUnderscorePropNamePool.get(str);
if (result == null) {
result = StringUtil.toUpperCaseWithUnderscore(str);
upperCaseWithUnderscorePropNamePool.put(str, result);
}
return result;
}
public static void toUpperCaseKeyWithUnderscore(final Map props) {
final Map tmp = Objectory.createLinkedHashMap();
for (Map.Entry entry : props.entrySet()) {
tmp.put(ClassUtil.toUpperCaseWithUnderscore(entry.getKey()), entry.getValue());
}
props.clear();
props.putAll(tmp);
Objectory.recycle(tmp);
}
static Set getIdFieldNames(final Class> targetClass) {
final Set idPropNames = new LinkedHashSet<>();
final Set allFields = new LinkedHashSet<>();
for (Class> superClass : ClassUtil.getAllSuperclasses(targetClass)) {
allFields.addAll(Array.asList(superClass.getDeclaredFields()));
}
allFields.addAll(Array.asList(targetClass.getDeclaredFields()));
for (Field field : allFields) {
if (ClassUtil.getPropGetMethod(targetClass, field.getName()) == null
&& ClassUtil.getPropGetMethod(targetClass, ClassUtil.formalizePropName(field.getName())) == null) {
continue;
}
if (field.isAnnotationPresent(Id.class) || field.isAnnotationPresent(ReadOnlyId.class)) {
idPropNames.add(field.getName());
} else {
try {
if (field.isAnnotationPresent(javax.persistence.Id.class)) {
idPropNames.add(field.getName());
}
} catch (Throwable e) {
// ignore
}
}
}
if (targetClass.isAnnotationPresent(Id.class)) {
String[] values = targetClass.getAnnotation(Id.class).value();
N.checkArgNotNullOrEmpty(values, "values for annotation @Id on Type/Class can't be null or empty");
idPropNames.addAll(Arrays.asList(values));
}
return idPropNames;
}
static Map checkPropGetMethodList(final Class> cls) {
Map getterMethodList = getPropGetMethodList(cls);
if (getterMethodList.size() == 0) {
throw new IllegalArgumentException("No property getter/setter method found in the specified entity: " + getCanonicalClassName(cls));
}
return getterMethodList;
}
static String makePackageFolder(String srcPath, final String pkgName) {
srcPath = (srcPath.endsWith("/") || srcPath.endsWith("\\")) ? srcPath : (srcPath + File.separator);
String classFilePath = (pkgName == null) ? srcPath : (srcPath + pkgName.replace('.', File.separatorChar) + File.separator);
File classFileFolder = new File(classFilePath);
if (!classFileFolder.exists()) {
classFileFolder.mkdirs();
}
return classFilePath;
}
// private static Class[] getTypeArguments(Class cls) {
// java.lang.reflect.Type[] typeArgs = null;
// java.lang.reflect.Type[] genericInterfaces = cls.getGenericInterfaces();
//
// if (notNullOrEmpty(genericInterfaces)) {
// for (java.lang.reflect.Type type : genericInterfaces) {
// typeArgs = ((ParameterizedType) type).getActualTypeArguments();
//
// if (notNullOrEmpty(typeArgs)) {
// break;
// }
// }
// } else {
// java.lang.reflect.Type genericSuperclass = cls.getGenericSuperclass();
//
// if (genericSuperclass != null) {
// typeArgs = ((ParameterizedType) genericSuperclass).getActualTypeArguments();
// }
// }
//
// if (notNullOrEmpty(typeArgs)) {
// Class[] clses = new Class[typeArgs.length];
//
// for (int i = 0; i < typeArgs.length; i++) {
// clses[i] = (Class) typeArgs[i];
// }
//
// return clses;
// } else {
// return null;
// }
// }
// /**
// * Returns the method declared in the specified {@code cls} with the specified method name.
// *
// * @param cls
// * @param methodName is case insensitive
// * @return {@code null} if no method is found by specified name
// */
// public static Method findDeclaredMethodByName(Class> cls, String methodName) {
// Method method = null;
//
// Method[] methods = cls.getDeclaredMethods();
//
// for (Method m : methods) {
// if (m.getName().equalsIgnoreCase(methodName)) {
// if ((method == null) || Modifier.isPublic(m.getModifiers())
// || (Modifier.isProtected(m.getModifiers()) && (!Modifier.isProtected(method.getModifiers())))
// || (!Modifier.isPrivate(m.getModifiers()) && Modifier.isPrivate(method.getModifiers()))) {
//
// method = m;
// }
//
// if (Modifier.isPublic(method.getModifiers())) {
// break;
// }
// }
// }
//
// // SHOULD NOT set it true here.
// // if (method != null) {
// // method.setAccessible(true);
// // }
//
// return method;
// }
static final class ClassMask {
static final String FIELD_MASK = "FIELD_MASK";
static final void methodMask() {
}
}
}