com.alibaba.fastjson.parser.ParserConfig Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fastjson-to-easyjson Show documentation
Show all versions of fastjson-to-easyjson Show documentation
Adapter alibaba fastjson to other json libraries. the fastjson version: 1.2.58
/*
* Copyright 2019 the original author or authors.
*
* Licensed under the Apache, 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.gnu.org/licenses/lgpl-3.0.html
*
* 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.fastjson.parser;
import com.alibaba.fastjson.*;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import com.alibaba.fastjson.asm.ClassReader;
import com.alibaba.fastjson.asm.TypeCollector;
import com.alibaba.fastjson.parser.deserializer.*;
import com.alibaba.fastjson.serializer.*;
import com.alibaba.fastjson.spi.Module;
import com.alibaba.fastjson.util.*;
import com.alibaba.fastjson.util.IdentityHashMap;
import com.alibaba.fastjson.util.ServiceLoader;
import javax.xml.datatype.XMLGregorianCalendar;
import java.io.Closeable;
import java.io.File;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.lang.reflect.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.*;
import java.nio.charset.Charset;
import java.security.AccessControlException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.*;
import java.util.regex.Pattern;
/**
* @author wenshao[[email protected]]
*/
public class ParserConfig {
public static final String DENY_PROPERTY = "fastjson.parser.deny";
public static final String AUTOTYPE_ACCEPT = "fastjson.parser.autoTypeAccept";
public static final String AUTOTYPE_SUPPORT_PROPERTY = "fastjson.parser.autoTypeSupport";
public static final String[] DENYS;
private static final String[] AUTO_TYPE_ACCEPT_LIST;
public static final boolean AUTO_SUPPORT;
static {
{
String property = IOUtils.getStringProperty(DENY_PROPERTY);
DENYS = splitItemsFormProperty(property);
}
{
String property = IOUtils.getStringProperty(AUTOTYPE_SUPPORT_PROPERTY);
AUTO_SUPPORT = "true".equals(property);
}
{
String property = IOUtils.getStringProperty(AUTOTYPE_ACCEPT);
String[] items = splitItemsFormProperty(property);
if (items == null) {
items = new String[0];
}
AUTO_TYPE_ACCEPT_LIST = items;
}
}
public static ParserConfig getGlobalInstance() {
return global;
}
public static ParserConfig global = new ParserConfig();
private final IdentityHashMap deserializers = new IdentityHashMap();
private final ConcurrentMap> typeMapping = new ConcurrentHashMap>(16, 0.75f, 1);
private boolean asmEnable = !ASMUtils.IS_ANDROID;
public final SymbolTable symbolTable = new SymbolTable(4096);
public PropertyNamingStrategy propertyNamingStrategy;
protected ClassLoader defaultClassLoader;
protected ASMDeserializerFactory asmFactory;
private static boolean awtError = false;
private static boolean jdk8Error = false;
private static boolean jodaError = false;
private static boolean guavaError = false;
private boolean autoTypeSupport = AUTO_SUPPORT;
private long[] denyHashCodes;
private long[] acceptHashCodes;
public final boolean fieldBased;
private boolean jacksonCompatible = false;
public boolean compatibleWithJavaBean = TypeUtils.compatibleWithJavaBean;
private List modules = new ArrayList();
{
denyHashCodes = new long[]{
-8720046426850100497L,
-8165637398350707645L,
-8109300701639721088L,
-8083514888460375884L,
-7966123100503199569L,
-7921218830998286408L,
-7768608037458185275L,
-7766605818834748097L,
-6835437086156813536L,
-6179589609550493385L,
-5194641081268104286L,
-4837536971810737970L,
-4082057040235125754L,
-3935185854875733362L,
-2753427844400776271L,
-2364987994247679115L,
-2262244760619952081L,
-1872417015366588117L,
-1589194880214235129L,
-254670111376247151L,
-190281065685395680L,
33238344207745342L,
313864100207897507L,
1073634739308289776L,
1203232727967308606L,
1459860845934817624L,
1502845958873959152L,
3547627781654598988L,
3730752432285826863L,
3794316665763266033L,
4147696707147271408L,
4904007817188630457L,
5347909877633654828L,
5450448828334921485L,
5688200883751798389L,
5751393439502795295L,
5944107969236155580L,
6742705432718011780L,
7017492163108594270L,
7179336928365889465L,
7442624256860549330L,
8389032537095247355L,
8409640769019589119L,
8838294710098435315L
};
long[] hashCodes = new long[AUTO_TYPE_ACCEPT_LIST.length + 1];
for (int i = 0; i < AUTO_TYPE_ACCEPT_LIST.length; i++) {
hashCodes[i] = TypeUtils.fnv1a_64(AUTO_TYPE_ACCEPT_LIST[i]);
}
hashCodes[hashCodes.length - 1] = -6293031534589903644L;
Arrays.sort(hashCodes);
acceptHashCodes = hashCodes;
}
public ParserConfig() {
this(false);
}
public ParserConfig(boolean fieldBase) {
this(null, null, fieldBase);
}
public ParserConfig(ClassLoader parentClassLoader) {
this(null, parentClassLoader, false);
}
public ParserConfig(ASMDeserializerFactory asmFactory) {
this(asmFactory, null, false);
}
private ParserConfig(ASMDeserializerFactory asmFactory, ClassLoader parentClassLoader, boolean fieldBased) {
this.fieldBased = fieldBased;
if (asmFactory == null && !ASMUtils.IS_ANDROID) {
try {
if (parentClassLoader == null) {
asmFactory = new ASMDeserializerFactory(new ASMClassLoader());
} else {
asmFactory = new ASMDeserializerFactory(parentClassLoader);
}
} catch (ExceptionInInitializerError error) {
// skip
} catch (AccessControlException error) {
// skip
} catch (NoClassDefFoundError error) {
// skip
}
}
this.asmFactory = asmFactory;
if (asmFactory == null) {
asmEnable = false;
}
initDeserializers();
addItemsToDeny(DENYS);
addItemsToAccept(AUTO_TYPE_ACCEPT_LIST);
}
private void initDeserializers() {
deserializers.put(SimpleDateFormat.class, MiscCodec.instance);
deserializers.put(java.sql.Timestamp.class, SqlDateDeserializer.instance_timestamp);
deserializers.put(java.sql.Date.class, SqlDateDeserializer.instance);
deserializers.put(java.sql.Time.class, TimeDeserializer.instance);
deserializers.put(Date.class, DateCodec.instance);
deserializers.put(Calendar.class, CalendarCodec.instance);
deserializers.put(XMLGregorianCalendar.class, CalendarCodec.instance);
deserializers.put(JSONObject.class, MapDeserializer.instance);
deserializers.put(JSONArray.class, CollectionCodec.instance);
deserializers.put(Map.class, MapDeserializer.instance);
deserializers.put(HashMap.class, MapDeserializer.instance);
deserializers.put(LinkedHashMap.class, MapDeserializer.instance);
deserializers.put(TreeMap.class, MapDeserializer.instance);
deserializers.put(ConcurrentMap.class, MapDeserializer.instance);
deserializers.put(ConcurrentHashMap.class, MapDeserializer.instance);
deserializers.put(Collection.class, CollectionCodec.instance);
deserializers.put(List.class, CollectionCodec.instance);
deserializers.put(ArrayList.class, CollectionCodec.instance);
deserializers.put(Object.class, JavaObjectDeserializer.instance);
deserializers.put(String.class, StringCodec.instance);
deserializers.put(StringBuffer.class, StringCodec.instance);
deserializers.put(StringBuilder.class, StringCodec.instance);
deserializers.put(char.class, CharacterCodec.instance);
deserializers.put(Character.class, CharacterCodec.instance);
deserializers.put(byte.class, NumberDeserializer.instance);
deserializers.put(Byte.class, NumberDeserializer.instance);
deserializers.put(short.class, NumberDeserializer.instance);
deserializers.put(Short.class, NumberDeserializer.instance);
deserializers.put(int.class, IntegerCodec.instance);
deserializers.put(Integer.class, IntegerCodec.instance);
deserializers.put(long.class, LongCodec.instance);
deserializers.put(Long.class, LongCodec.instance);
deserializers.put(BigInteger.class, BigIntegerCodec.instance);
deserializers.put(BigDecimal.class, BigDecimalCodec.instance);
deserializers.put(float.class, FloatCodec.instance);
deserializers.put(Float.class, FloatCodec.instance);
deserializers.put(double.class, NumberDeserializer.instance);
deserializers.put(Double.class, NumberDeserializer.instance);
deserializers.put(boolean.class, BooleanCodec.instance);
deserializers.put(Boolean.class, BooleanCodec.instance);
deserializers.put(Class.class, MiscCodec.instance);
deserializers.put(char[].class, new CharArrayCodec());
deserializers.put(AtomicBoolean.class, BooleanCodec.instance);
deserializers.put(AtomicInteger.class, IntegerCodec.instance);
deserializers.put(AtomicLong.class, LongCodec.instance);
deserializers.put(AtomicReference.class, ReferenceCodec.instance);
deserializers.put(WeakReference.class, ReferenceCodec.instance);
deserializers.put(SoftReference.class, ReferenceCodec.instance);
deserializers.put(UUID.class, MiscCodec.instance);
deserializers.put(TimeZone.class, MiscCodec.instance);
deserializers.put(Locale.class, MiscCodec.instance);
deserializers.put(Currency.class, MiscCodec.instance);
deserializers.put(Inet4Address.class, MiscCodec.instance);
deserializers.put(Inet6Address.class, MiscCodec.instance);
deserializers.put(InetSocketAddress.class, MiscCodec.instance);
deserializers.put(File.class, MiscCodec.instance);
deserializers.put(URI.class, MiscCodec.instance);
deserializers.put(URL.class, MiscCodec.instance);
deserializers.put(Pattern.class, MiscCodec.instance);
deserializers.put(Charset.class, MiscCodec.instance);
deserializers.put(JSONPath.class, MiscCodec.instance);
deserializers.put(Number.class, NumberDeserializer.instance);
deserializers.put(AtomicIntegerArray.class, AtomicCodec.instance);
deserializers.put(AtomicLongArray.class, AtomicCodec.instance);
deserializers.put(StackTraceElement.class, StackTraceElementDeserializer.instance);
deserializers.put(Serializable.class, JavaObjectDeserializer.instance);
deserializers.put(Cloneable.class, JavaObjectDeserializer.instance);
deserializers.put(Comparable.class, JavaObjectDeserializer.instance);
deserializers.put(Closeable.class, JavaObjectDeserializer.instance);
deserializers.put(JSONPObject.class, new JSONPDeserializer());
}
private static String[] splitItemsFormProperty(final String property) {
if (property != null && property.length() > 0) {
return property.split(",");
}
return null;
}
public void configFromPropety(Properties properties) {
{
String property = properties.getProperty(DENY_PROPERTY);
String[] items = splitItemsFormProperty(property);
addItemsToDeny(items);
}
{
String property = properties.getProperty(AUTOTYPE_ACCEPT);
String[] items = splitItemsFormProperty(property);
addItemsToAccept(items);
}
{
String property = properties.getProperty(AUTOTYPE_SUPPORT_PROPERTY);
if ("true".equals(property)) {
this.autoTypeSupport = true;
} else if ("false".equals(property)) {
this.autoTypeSupport = false;
}
}
}
private void addItemsToDeny(final String[] items) {
if (items == null) {
return;
}
for (int i = 0; i < items.length; ++i) {
String item = items[i];
this.addDeny(item);
}
}
private void addItemsToAccept(final String[] items) {
if (items == null) {
return;
}
for (int i = 0; i < items.length; ++i) {
String item = items[i];
this.addAccept(item);
}
}
public boolean isAutoTypeSupport() {
return autoTypeSupport;
}
public void setAutoTypeSupport(boolean autoTypeSupport) {
this.autoTypeSupport = autoTypeSupport;
}
public boolean isAsmEnable() {
return asmEnable;
}
public void setAsmEnable(boolean asmEnable) {
this.asmEnable = asmEnable;
}
/**
* @deprecated
*/
public IdentityHashMap getDerializers() {
return deserializers;
}
public IdentityHashMap getDeserializers() {
return deserializers;
}
public ObjectDeserializer getDeserializer(Type type) {
ObjectDeserializer derializer = this.deserializers.get(type);
if (derializer != null) {
return derializer;
}
if (type instanceof Class>) {
return getDeserializer((Class>) type, type);
}
if (type instanceof ParameterizedType) {
Type rawType = ((ParameterizedType) type).getRawType();
if (rawType instanceof Class>) {
return getDeserializer((Class>) rawType, type);
} else {
return getDeserializer(rawType);
}
}
if (type instanceof WildcardType) {
WildcardType wildcardType = (WildcardType) type;
Type[] upperBounds = wildcardType.getUpperBounds();
if (upperBounds.length == 1) {
Type upperBoundType = upperBounds[0];
return getDeserializer(upperBoundType);
}
}
return JavaObjectDeserializer.instance;
}
public ObjectDeserializer getDeserializer(Class> clazz, Type type) {
ObjectDeserializer derializer = deserializers.get(type);
if (derializer != null) {
return derializer;
}
if (type == null) {
type = clazz;
}
derializer = deserializers.get(type);
if (derializer != null) {
return derializer;
}
{
JSONType annotation = TypeUtils.getAnnotation(clazz, JSONType.class);
if (annotation != null) {
Class> mappingTo = annotation.mappingTo();
if (mappingTo != Void.class) {
return getDeserializer(mappingTo, mappingTo);
}
}
}
if (type instanceof WildcardType || type instanceof TypeVariable || type instanceof ParameterizedType) {
derializer = deserializers.get(clazz);
}
if (derializer != null) {
return derializer;
}
for (Module module : modules) {
derializer = module.createDeserializer(this, clazz);
if (derializer != null) {
putDeserializer(type, derializer);
return derializer;
}
}
String className = clazz.getName();
className = className.replace('$', '.');
if (className.startsWith("java.awt.") //
&& AwtCodec.support(clazz)) {
if (!awtError) {
String[] names = new String[]{
"java.awt.Point",
"java.awt.Font",
"java.awt.Rectangle",
"java.awt.Color"
};
try {
for (String name : names) {
if (name.equals(className)) {
deserializers.put(Class.forName(name), derializer = AwtCodec.instance);
return derializer;
}
}
} catch (Throwable e) {
// skip
awtError = true;
}
derializer = AwtCodec.instance;
}
}
if (!jdk8Error) {
try {
if (className.startsWith("java.time.")) {
String[] names = new String[]{
"java.time.LocalDateTime",
"java.time.LocalDate",
"java.time.LocalTime",
"java.time.ZonedDateTime",
"java.time.OffsetDateTime",
"java.time.OffsetTime",
"java.time.ZoneOffset",
"java.time.ZoneRegion",
"java.time.ZoneId",
"java.time.Period",
"java.time.Duration",
"java.time.Instant"
};
for (String name : names) {
if (name.equals(className)) {
return derializer;
}
}
} else if (className.startsWith("java.util.Optional")) {
String[] names = new String[]{
"java.util.Optional",
"java.util.OptionalDouble",
"java.util.OptionalInt",
"java.util.OptionalLong"
};
for (String name : names) {
if (name.equals(className)) {
return derializer;
}
}
}
} catch (Throwable e) {
// skip
jdk8Error = true;
}
}
if (!jodaError) {
try {
if (className.startsWith("org.joda.time.")) {
String[] names = new String[]{
"org.joda.time.DateTime",
"org.joda.time.LocalDate",
"org.joda.time.LocalDateTime",
"org.joda.time.LocalTime",
"org.joda.time.Instant",
"org.joda.time.Period",
"org.joda.time.Duration",
"org.joda.time.DateTimeZone",
"org.joda.time.format.DateTimeFormatter"
};
for (String name : names) {
if (name.equals(className)) {
deserializers.put(Class.forName(name), derializer = JodaCodec.instance);
return derializer;
}
}
}
} catch (Throwable e) {
// skip
jodaError = true;
}
}
if ((!guavaError) //
&& className.startsWith("com.google.common.collect.")) {
try {
String[] names = new String[]{
"com.google.common.collect.HashMultimap",
"com.google.common.collect.LinkedListMultimap",
"com.google.common.collect.LinkedHashMultimap",
"com.google.common.collect.ArrayListMultimap",
"com.google.common.collect.TreeMultimap"
};
for (String name : names) {
if (name.equals(className)) {
deserializers.put(Class.forName(name), derializer = GuavaCodec.instance);
return derializer;
}
}
} catch (ClassNotFoundException e) {
// skip
guavaError = true;
}
}
if (className.equals("java.nio.ByteBuffer")) {
deserializers.put(clazz, derializer = ByteBufferCodec.instance);
}
if (className.equals("java.nio.file.Path")) {
deserializers.put(clazz, derializer = MiscCodec.instance);
}
if (clazz == Map.Entry.class) {
deserializers.put(clazz, derializer = MiscCodec.instance);
}
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
for (AutowiredObjectDeserializer autowired : ServiceLoader.load(AutowiredObjectDeserializer.class,
classLoader)) {
for (Type forType : autowired.getAutowiredFor()) {
deserializers.put(forType, autowired);
}
}
} catch (Exception ex) {
// skip
}
if (derializer == null) {
derializer = deserializers.get(type);
}
if (derializer != null) {
return derializer;
}
if (clazz.isEnum()) {
if (jacksonCompatible) {
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (TypeUtils.isJacksonCreator(method)) {
derializer = createJavaBeanDeserializer(clazz, type);
putDeserializer(type, derializer);
return derializer;
}
}
}
Class> deserClass = null;
JSONType jsonType = clazz.getAnnotation(JSONType.class);
if (jsonType != null) {
deserClass = jsonType.deserializer();
try {
derializer = (ObjectDeserializer) deserClass.newInstance();
deserializers.put(clazz, derializer);
return derializer;
} catch (Throwable error) {
// skip
}
}
derializer = new EnumDeserializer(clazz);
} else if (clazz.isArray()) {
derializer = ObjectArrayCodec.instance;
} else if (clazz == Set.class || clazz == HashSet.class || clazz == Collection.class || clazz == List.class
|| clazz == ArrayList.class) {
derializer = CollectionCodec.instance;
} else if (Collection.class.isAssignableFrom(clazz)) {
derializer = CollectionCodec.instance;
} else if (Map.class.isAssignableFrom(clazz)) {
derializer = MapDeserializer.instance;
} else if (Throwable.class.isAssignableFrom(clazz)) {
derializer = new ThrowableDeserializer(this, clazz);
} else if (PropertyProcessable.class.isAssignableFrom(clazz)) {
derializer = new PropertyProcessableDeserializer((Class) clazz);
} else if (clazz == InetAddress.class) {
derializer = MiscCodec.instance;
} else {
derializer = createJavaBeanDeserializer(clazz, type);
}
putDeserializer(type, derializer);
return derializer;
}
/**
* @since 1.2.25
*/
public void initJavaBeanDeserializers(Class>... classes) {
if (classes == null) {
return;
}
for (Class> type : classes) {
if (type == null) {
continue;
}
ObjectDeserializer deserializer = createJavaBeanDeserializer(type, type);
putDeserializer(type, deserializer);
}
}
public ObjectDeserializer createJavaBeanDeserializer(Class> clazz, Type type) {
boolean asmEnable = this.asmEnable & !this.fieldBased;
if (asmEnable) {
JSONType jsonType = TypeUtils.getAnnotation(clazz, JSONType.class);
if (jsonType != null) {
Class> deserializerClass = jsonType.deserializer();
if (deserializerClass != Void.class) {
try {
Object deseralizer = deserializerClass.newInstance();
if (deseralizer instanceof ObjectDeserializer) {
return (ObjectDeserializer) deseralizer;
}
} catch (Throwable e) {
// skip
}
}
asmEnable = jsonType.asm();
}
if (asmEnable) {
Class> superClass = JavaBeanInfo.getBuilderClass(clazz, jsonType);
if (superClass == null) {
superClass = clazz;
}
for (; ; ) {
if (!Modifier.isPublic(superClass.getModifiers())) {
asmEnable = false;
break;
}
superClass = superClass.getSuperclass();
if (superClass == Object.class || superClass == null) {
break;
}
}
}
}
if (clazz.getTypeParameters().length != 0) {
asmEnable = false;
}
if (asmEnable && asmFactory != null && asmFactory.classLoader.isExternalClass(clazz)) {
asmEnable = false;
}
if (asmEnable) {
asmEnable = ASMUtils.checkName(clazz.getSimpleName());
}
if (asmEnable) {
if (clazz.isInterface()) {
asmEnable = false;
}
JavaBeanInfo beanInfo = JavaBeanInfo.build(clazz
, type
, propertyNamingStrategy
, false
, TypeUtils.compatibleWithJavaBean
, jacksonCompatible
);
if (asmEnable && beanInfo.fields.length > 200) {
asmEnable = false;
}
Constructor> defaultConstructor = beanInfo.defaultConstructor;
if (asmEnable && defaultConstructor == null && !clazz.isInterface()) {
asmEnable = false;
}
for (FieldInfo fieldInfo : beanInfo.fields) {
if (fieldInfo.getOnly) {
asmEnable = false;
break;
}
Class> fieldClass = fieldInfo.fieldClass;
if (!Modifier.isPublic(fieldClass.getModifiers())) {
asmEnable = false;
break;
}
if (fieldClass.isMemberClass() && !Modifier.isStatic(fieldClass.getModifiers())) {
asmEnable = false;
break;
}
if (fieldInfo.getMember() != null //
&& !ASMUtils.checkName(fieldInfo.getMember().getName())) {
asmEnable = false;
break;
}
JSONField annotation = fieldInfo.getAnnotation();
if (annotation != null //
&& ((!ASMUtils.checkName(annotation.name())) //
|| annotation.format().length() != 0 //
|| annotation.deserializeUsing() != Void.class //
|| annotation.unwrapped())
|| (fieldInfo.method != null && fieldInfo.method.getParameterTypes().length > 1)) {
asmEnable = false;
break;
}
if (fieldClass.isEnum()) { // EnumDeserializer
ObjectDeserializer fieldDeser = this.getDeserializer(fieldClass);
if (!(fieldDeser instanceof EnumDeserializer)) {
asmEnable = false;
break;
}
}
}
}
if (asmEnable) {
if (clazz.isMemberClass() && !Modifier.isStatic(clazz.getModifiers())) {
asmEnable = false;
}
}
if (asmEnable) {
if (TypeUtils.isXmlField(clazz)) {
asmEnable = false;
}
}
if (!asmEnable) {
return new JavaBeanDeserializer(this, clazz, type);
}
JavaBeanInfo beanInfo = JavaBeanInfo.build(clazz, type, propertyNamingStrategy);
try {
return asmFactory.createJavaBeanDeserializer(this, beanInfo);
// } catch (VerifyError e) {
// e.printStackTrace();
// return new JavaBeanDeserializer(this, clazz, type);
} catch (NoSuchMethodException ex) {
return new JavaBeanDeserializer(this, clazz, type);
} catch (JSONException asmError) {
return new JavaBeanDeserializer(this, beanInfo);
} catch (Exception e) {
throw new JSONException("create asm deserializer error, " + clazz.getName(), e);
}
}
public FieldDeserializer createFieldDeserializer(ParserConfig mapping, //
JavaBeanInfo beanInfo, //
FieldInfo fieldInfo) {
Class> clazz = beanInfo.clazz;
Class> fieldClass = fieldInfo.fieldClass;
Class> deserializeUsing = null;
JSONField annotation = fieldInfo.getAnnotation();
if (annotation != null) {
deserializeUsing = annotation.deserializeUsing();
if (deserializeUsing == Void.class) {
deserializeUsing = null;
}
}
if (deserializeUsing == null && (fieldClass == List.class || fieldClass == ArrayList.class)) {
return new ArrayListTypeFieldDeserializer(mapping, clazz, fieldInfo);
}
return new DefaultFieldDeserializer(mapping, clazz, fieldInfo);
}
public void putDeserializer(Type type, ObjectDeserializer deserializer) {
deserializers.put(type, deserializer);
}
public ObjectDeserializer getDeserializer(FieldInfo fieldInfo) {
return getDeserializer(fieldInfo.fieldClass, fieldInfo.fieldType);
}
/**
* @deprecated internal method, dont call
*/
public boolean isPrimitive(Class> clazz) {
return isPrimitive2(clazz);
}
/**
* @deprecated internal method, dont call
*/
public static boolean isPrimitive2(Class> clazz) {
return clazz.isPrimitive() //
|| clazz == Boolean.class //
|| clazz == Character.class //
|| clazz == Byte.class //
|| clazz == Short.class //
|| clazz == Integer.class //
|| clazz == Long.class //
|| clazz == Float.class //
|| clazz == Double.class //
|| clazz == BigInteger.class //
|| clazz == BigDecimal.class //
|| clazz == String.class //
|| clazz == Date.class //
|| clazz == java.sql.Date.class //
|| clazz == java.sql.Time.class //
|| clazz == java.sql.Timestamp.class //
|| clazz.isEnum() //
;
}
/**
* fieldName,field ,先生成fieldName的快照,减少之后的findField的轮询
*
* @param clazz
* @param fieldCacheMap :map<fieldName ,Field>
*/
public static void parserAllFieldToCache(Class> clazz, Map**fieldName*/String, Field> fieldCacheMap) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
String fieldName = field.getName();
if (!fieldCacheMap.containsKey(fieldName)) {
fieldCacheMap.put(fieldName, field);
}
}
if (clazz.getSuperclass() != null && clazz.getSuperclass() != Object.class) {
parserAllFieldToCache(clazz.getSuperclass(), fieldCacheMap);
}
}
public static Field getFieldFromCache(String fieldName, Map fieldCacheMap) {
Field field = fieldCacheMap.get(fieldName);
if (field == null) {
field = fieldCacheMap.get("_" + fieldName);
}
if (field == null) {
field = fieldCacheMap.get("m_" + fieldName);
}
if (field == null) {
char c0 = fieldName.charAt(0);
if (c0 >= 'a' && c0 <= 'z') {
char[] chars = fieldName.toCharArray();
chars[0] -= 32; // lower
String fieldNameX = new String(chars);
field = fieldCacheMap.get(fieldNameX);
}
if (fieldName.length() > 2) {
char c1 = fieldName.charAt(1);
if (fieldName.length() > 2
&& c0 >= 'a' && c0 <= 'z'
&& c1 >= 'A' && c1 <= 'Z') {
for (Map.Entry entry : fieldCacheMap.entrySet()) {
if (fieldName.equalsIgnoreCase(entry.getKey())) {
field = entry.getValue();
break;
}
}
}
}
}
return field;
}
public ClassLoader getDefaultClassLoader() {
return defaultClassLoader;
}
public void setDefaultClassLoader(ClassLoader defaultClassLoader) {
this.defaultClassLoader = defaultClassLoader;
}
public void addDeny(String name) {
if (name == null || name.length() == 0) {
return;
}
long hash = TypeUtils.fnv1a_64(name);
if (Arrays.binarySearch(this.denyHashCodes, hash) >= 0) {
return;
}
long[] hashCodes = new long[this.denyHashCodes.length + 1];
hashCodes[hashCodes.length - 1] = hash;
System.arraycopy(this.denyHashCodes, 0, hashCodes, 0, this.denyHashCodes.length);
Arrays.sort(hashCodes);
this.denyHashCodes = hashCodes;
}
public void addAccept(String name) {
if (name == null || name.length() == 0) {
return;
}
long hash = TypeUtils.fnv1a_64(name);
if (Arrays.binarySearch(this.acceptHashCodes, hash) >= 0) {
return;
}
long[] hashCodes = new long[this.acceptHashCodes.length + 1];
hashCodes[hashCodes.length - 1] = hash;
System.arraycopy(this.acceptHashCodes, 0, hashCodes, 0, this.acceptHashCodes.length);
Arrays.sort(hashCodes);
this.acceptHashCodes = hashCodes;
}
public Class> checkAutoType(Class type) {
if (deserializers.get(type) != null) {
return type;
}
return checkAutoType(type.getName(), null, JSON.DEFAULT_PARSER_FEATURE);
}
public Class> checkAutoType(String typeName, Class> expectClass) {
return checkAutoType(typeName, expectClass, JSON.DEFAULT_PARSER_FEATURE);
}
public Class> checkAutoType(String typeName, Class> expectClass, int features) {
if (typeName == null) {
return null;
}
if (typeName.length() >= 192 || typeName.length() < 3) {
throw new JSONException("autoType is not support. " + typeName);
}
final boolean expectClassFlag;
if (expectClass == null) {
expectClassFlag = false;
} else {
if (expectClass == Object.class
|| expectClass == Serializable.class
|| expectClass == Cloneable.class
|| expectClass == Closeable.class
|| expectClass == EventListener.class
|| expectClass == Iterable.class
|| expectClass == Collection.class
) {
expectClassFlag = false;
} else {
expectClassFlag = true;
}
}
String className = typeName.replace('$', '.');
Class> clazz = null;
final long BASIC = 0xcbf29ce484222325L;
final long PRIME = 0x100000001b3L;
final long h1 = (BASIC ^ className.charAt(0)) * PRIME;
if (h1 == 0xaf64164c86024f1aL) { // [
throw new JSONException("autoType is not support. " + typeName);
}
if ((h1 ^ className.charAt(className.length() - 1)) * PRIME == 0x9198507b5af98f0L) {
throw new JSONException("autoType is not support. " + typeName);
}
final long h3 = (((((BASIC ^ className.charAt(0))
* PRIME)
^ className.charAt(1))
* PRIME)
^ className.charAt(2))
* PRIME;
if (autoTypeSupport || expectClassFlag) {
long hash = h3;
for (int i = 3; i < className.length(); ++i) {
hash ^= className.charAt(i);
hash *= PRIME;
if (Arrays.binarySearch(acceptHashCodes, hash) >= 0) {
clazz = TypeUtils.loadClass(typeName, defaultClassLoader, true);
if (clazz != null) {
return clazz;
}
}
if (Arrays.binarySearch(denyHashCodes, hash) >= 0 && TypeUtils.getClassFromMapping(typeName) == null) {
throw new JSONException("autoType is not support. " + typeName);
}
}
}
if (clazz == null) {
clazz = TypeUtils.getClassFromMapping(typeName);
}
if (clazz == null) {
clazz = deserializers.findClass(typeName);
}
if (clazz == null) {
clazz = typeMapping.get(typeName);
}
if (clazz != null) {
if (expectClass != null
&& clazz != HashMap.class
&& !expectClass.isAssignableFrom(clazz)) {
throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());
}
return clazz;
}
if (!autoTypeSupport) {
long hash = h3;
for (int i = 3; i < className.length(); ++i) {
char c = className.charAt(i);
hash ^= c;
hash *= PRIME;
if (Arrays.binarySearch(denyHashCodes, hash) >= 0) {
throw new JSONException("autoType is not support. " + typeName);
}
// white list
if (Arrays.binarySearch(acceptHashCodes, hash) >= 0) {
if (clazz == null) {
clazz = TypeUtils.loadClass(typeName, defaultClassLoader, true);
}
if (expectClass != null && expectClass.isAssignableFrom(clazz)) {
throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());
}
return clazz;
}
}
}
boolean jsonType = false;
InputStream is = null;
try {
String resource = typeName.replace('.', '/') + ".class";
if (defaultClassLoader != null) {
is = defaultClassLoader.getResourceAsStream(resource);
} else {
is = ParserConfig.class.getClassLoader().getResourceAsStream(resource);
}
if (is != null) {
ClassReader classReader = new ClassReader(is, true);
TypeCollector visitor = new TypeCollector("", new Class[0]);
classReader.accept(visitor);
jsonType = visitor.hasJsonType();
}
} catch (Exception e) {
// skip
} finally {
IOUtils.close(is);
}
final int mask = Feature.SupportAutoType.mask;
boolean autoTypeSupport = this.autoTypeSupport
|| (features & mask) != 0
|| (JSON.DEFAULT_PARSER_FEATURE & mask) != 0;
if (clazz == null && (autoTypeSupport || jsonType || expectClassFlag)) {
boolean cacheClass = autoTypeSupport || jsonType;
clazz = TypeUtils.loadClass(typeName, defaultClassLoader, cacheClass);
}
if (clazz != null) {
if (jsonType) {
TypeUtils.addMapping(typeName, clazz);
return clazz;
}
if (ClassLoader.class.isAssignableFrom(clazz) // classloader is danger
|| javax.sql.DataSource.class.isAssignableFrom(clazz) // dataSource can load jdbc driver
|| javax.sql.RowSet.class.isAssignableFrom(clazz) //
) {
throw new JSONException("autoType is not support. " + typeName);
}
if (expectClass != null) {
if (expectClass.isAssignableFrom(clazz)) {
TypeUtils.addMapping(typeName, clazz);
return clazz;
} else {
throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());
}
}
JavaBeanInfo beanInfo = JavaBeanInfo.build(clazz, clazz, propertyNamingStrategy);
if (beanInfo.creatorConstructor != null && autoTypeSupport) {
throw new JSONException("autoType is not support. " + typeName);
}
}
if (!autoTypeSupport) {
throw new JSONException("autoType is not support. " + typeName);
}
if (clazz != null) {
TypeUtils.addMapping(typeName, clazz);
}
return clazz;
}
public void clearDeserializers() {
this.deserializers.clear();
this.initDeserializers();
}
public boolean isJacksonCompatible() {
return jacksonCompatible;
}
public void setJacksonCompatible(boolean jacksonCompatible) {
this.jacksonCompatible = jacksonCompatible;
}
public void register(String typeName, Class type) {
typeMapping.putIfAbsent(typeName, type);
}
public void register(Module module) {
this.modules.add(module);
}
}