Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,29 @@
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.CharacterIterator;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.text.StringCharacterIterator;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.ArrayDeque;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Stack;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Pattern;
Expand All @@ -60,23 +70,22 @@ public class DefaultJSONWriter implements JSONWriter {

private static final Logger LOG = LogManager.getLogger(DefaultJSONWriter.class);

private static char[] hex = "0123456789ABCDEF".toCharArray();
private static final char[] hex = "0123456789ABCDEF".toCharArray();

private static final ConcurrentMap<Class<?>, BeanInfo> BEAN_INFO_CACHE_IGNORE_HIERARCHY = new ConcurrentHashMap<>();
private static final ConcurrentMap<Class<?>, BeanInfo> BEAN_INFO_CACHE = new ConcurrentHashMap<>();

private StringBuilder buf = new StringBuilder();
private Stack<Object> stack = new Stack<>();
private final StringBuilder buf = new StringBuilder();
private final Deque<Object> stack = new ArrayDeque<>();
private boolean ignoreHierarchy = true;
private Object root;
private boolean buildExpr = true;
private String exprStack = "";
private Collection<Pattern> excludeProperties;
private Collection<Pattern> includeProperties;
private DateFormat formatter;
private DateFormat dateFormat;
private boolean enumAsBean = ENUM_AS_BEAN_DEFAULT;
private boolean excludeNullProperties;
private boolean cacheBeanInfo = true;
private boolean excludeProxyProperties;
private ProxyService proxyService;

Expand All @@ -101,14 +110,10 @@ public String write(Object object) throws JSONException {
}

/**
* @param object
* Object to be serialized into JSON
* @param excludeProperties
* Patterns matching properties to ignore
* @param includeProperties
* Patterns matching properties to include
* @param excludeNullProperties
* enable/disable excluding of null properties
* @param object Object to be serialized into JSON
* @param excludeProperties Patterns matching properties to ignore
* @param includeProperties Patterns matching properties to include
* @param excludeNullProperties enable/disable excluding of null properties
* @return JSON string for object
* @throws JSONException in case of error during serialize
*/
Expand All @@ -134,7 +139,6 @@ public String write(Object object, Collection<Pattern> excludeProperties,
*
* @param object Object to be serialized into JSON
* @param method method
*
* @throws JSONException in case of error during serialize
*/
protected void value(Object object, Method method) throws JSONException {
Expand All @@ -144,7 +148,7 @@ protected void value(Object object, Method method) throws JSONException {
}

if (this.stack.contains(object)) {
Class clazz = object.getClass();
Class<?> clazz = object.getClass();

// cyclic reference
if (clazz.isPrimitive() || clazz.equals(String.class)) {
Expand All @@ -165,8 +169,7 @@ protected void value(Object object, Method method) throws JSONException {
*
* @param object Object to be serialized into JSON
* @param method method
*
* @throws JSONException in case of error during serialize
* @throws JSONException in case of error during serialize
*/
protected void process(Object object, Method method) throws JSONException {
this.stack.push(object);
Expand All @@ -181,20 +184,22 @@ protected void process(Object object, Method method) throws JSONException {
this.string(object);
} else if (object instanceof Character) {
this.string(object);
} else if (object instanceof Map) {
this.map((Map) object, method);
} else if (object instanceof Map<?, ?> map) {
this.map(map, method);
} else if (object.getClass().isArray()) {
this.array(object, method);
} else if (object instanceof Iterable) {
this.array(((Iterable) object).iterator(), method);
} else if (object instanceof Iterable<?> iterable) {
this.array(iterable.iterator(), method);
} else if (object instanceof Date) {
this.date((Date) object, method);
} else if (object instanceof Calendar) {
this.date(((Calendar) object).getTime(), method);
} else if (object instanceof TemporalAccessor temporalAccessor) {
this.temporal(temporalAccessor, method);
} else if (object instanceof Locale) {
this.string(object);
} else if (object instanceof Enum) {
this.enumeration((Enum) object);
} else if (object instanceof Enum<?> enumValue) {
this.enumeration(enumValue);
} else {
processCustom(object, method);
}
Expand All @@ -207,8 +212,7 @@ protected void process(Object object, Method method) throws JSONException {
*
* @param object object
* @param method method
*
* @throws JSONException in case of error during serialize
* @throws JSONException in case of error during serialize
*/
protected void processCustom(Object object, Method method) throws JSONException {
this.bean(object);
Expand All @@ -218,8 +222,7 @@ protected void processCustom(Object object, Method method) throws JSONException
* Instrospect bean and serialize its properties
*
* @param object object
*
* @throws JSONException in case of error during serialize
* @throws JSONException in case of error during serialize
*/
protected void bean(Object object) throws JSONException {
this.add("{");
Expand Down Expand Up @@ -279,7 +282,7 @@ protected void bean(Object object) throws JSONException {
// special-case handling for an Enumeration - include the name() as
// a property */
if (object instanceof Enum) {
Object value = ((Enum) object).name();
Object value = ((Enum<?>) object).name();
this.add("_name", value, object.getClass().getMethod("name"), hasData);
}
} catch (Exception e) {
Expand Down Expand Up @@ -309,11 +312,11 @@ protected BeanInfo getBeanInfo(final Class<?> clazz) throws IntrospectionExcepti
return beanInfo;
}

protected Object getBridgedValue(Method baseAccessor, Object value) throws InstantiationException, IllegalAccessException {
protected Object getBridgedValue(Method baseAccessor, Object value) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
JSONFieldBridge fieldBridgeAnn = baseAccessor.getAnnotation(JSONFieldBridge.class);
if (fieldBridgeAnn != null) {
Class impl = fieldBridgeAnn.impl();
FieldBridge instance = (FieldBridge) impl.newInstance();
Class<?> impl = fieldBridgeAnn.impl();
FieldBridge instance = (FieldBridge) impl.getDeclaredConstructor().newInstance();

if (fieldBridgeAnn.params().length > 0 && ParameterizedBridge.class.isAssignableFrom(impl)) {
Map<String, String> params = new HashMap<>(fieldBridgeAnn.params().length);
Expand All @@ -327,7 +330,7 @@ protected Object getBridgedValue(Method baseAccessor, Object value) throws Insta
return value;
}

protected Method findBaseAccessor(Class clazz, Method accessor) {
protected Method findBaseAccessor(Class<?> clazz, Method accessor) {
Method baseAccessor = null;
if (clazz.getName().contains("$$EnhancerByCGLIB$$")) {
try {
Expand All @@ -340,23 +343,22 @@ protected Method findBaseAccessor(Class clazz, Method accessor) {
} else if (clazz.getName().contains("$$_javassist")) {
try {
baseAccessor = Class.forName(
clazz.getName().substring(0, clazz.getName().indexOf("_$$")))
clazz.getName().substring(0, clazz.getName().indexOf("_$$")))
.getMethod(accessor.getName(), accessor.getParameterTypes());
} catch (Exception ex) {
LOG.debug(ex.getMessage(), ex);
}

//in hibernate4.3.7,because javassist3.18.1's class name generate rule is '_$$_jvst'+...
} else if(clazz.getName().contains("$$_jvst")){
//in hibernate4.3.7,because javassist3.18.1's class name generate rule is '_$$_jvst'+...
} else if (clazz.getName().contains("$$_jvst")) {
try {
baseAccessor = Class.forName(
clazz.getName().substring(0, clazz.getName().indexOf("_$$")))
clazz.getName().substring(0, clazz.getName().indexOf("_$$")))
.getMethod(accessor.getName(), accessor.getParameterTypes());
} catch (Exception ex) {
LOG.debug(ex.getMessage(), ex);
}
}
else {
} else {
return accessor;
}
return baseAccessor;
Expand All @@ -367,18 +369,17 @@ protected Method findBaseAccessor(Class clazz, Method accessor) {
* including all its own properties
*
* @param enumeration the enum
*
* @throws JSONException in case of error during serialize
* @throws JSONException in case of error during serialize
*/
protected void enumeration(Enum enumeration) throws JSONException {
protected void enumeration(Enum<?> enumeration) throws JSONException {
if (enumAsBean) {
this.bean(enumeration);
} else {
this.string(enumeration.name());
}
}

protected boolean shouldExcludeProperty(PropertyDescriptor prop) throws SecurityException, NoSuchFieldException {
protected boolean shouldExcludeProperty(PropertyDescriptor prop) throws SecurityException {
String name = prop.getName();
return name.equals("class")
|| name.equals("declaringClass")
Expand All @@ -391,7 +392,7 @@ protected String expandExpr(int i) {
}

protected String expandExpr(String property) {
if (this.exprStack.length() == 0) {
if (this.exprStack.isEmpty()) {
return property;
}
return this.exprStack + "." + property;
Expand Down Expand Up @@ -421,7 +422,7 @@ protected boolean shouldExcludeProperty(String expr) {
return false;
}
}
if (LOG.isDebugEnabled()){
if (LOG.isDebugEnabled()) {
LOG.debug("Ignoring property because of include rule: " + expr);
}
return true;
Expand Down Expand Up @@ -449,15 +450,15 @@ protected boolean add(String name, Object value, Method method, boolean hasData)
/*
* Add map to buffer
*/
protected void map(Map map, Method method) throws JSONException {
protected void map(Map<?, ?> map, Method method) throws JSONException {
this.add("{");

Iterator it = map.entrySet().iterator();
Iterator<?> it = map.entrySet().iterator();

boolean warnedNonString = false; // one report per map
boolean hasData = false;
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) it.next();
if (excludeNullProperties && entry.getValue() == null) {
continue;
}
Expand Down Expand Up @@ -504,18 +505,53 @@ protected void date(Date date, Method method) {
JSON json = null;
if (method != null)
json = method.getAnnotation(JSON.class);
if (this.formatter == null)
this.formatter = new SimpleDateFormat(JSONUtil.RFC3339_FORMAT);
if (this.dateFormat == null)
this.dateFormat = new SimpleDateFormat(JSONUtil.RFC3339_FORMAT);

DateFormat formatter = (json != null) && (json.format().length() > 0) ? new SimpleDateFormat(json
.format()) : this.formatter;
DateFormat formatter = (json != null) && (!json.format().isEmpty()) ? new SimpleDateFormat(json
.format()) : this.dateFormat;
this.string(formatter.format(date));
}

/*
* Add temporal (java.time) value to buffer
*/
protected void temporal(TemporalAccessor temporal, Method method) {
JSON json = null;
if (method != null) {
json = method.getAnnotation(JSON.class);
}

DateTimeFormatter formatter;
if (json != null && !json.format().isEmpty()) {
formatter = DateTimeFormatter.ofPattern(json.format());
} else {
formatter = getDefaultDateTimeFormatter(temporal);
}
this.string(formatter.format(temporal));
}

private static DateTimeFormatter getDefaultDateTimeFormatter(TemporalAccessor temporal) {
if (temporal instanceof LocalDate) {
return DateTimeFormatter.ISO_LOCAL_DATE;
} else if (temporal instanceof LocalDateTime) {
return DateTimeFormatter.ISO_LOCAL_DATE_TIME;
} else if (temporal instanceof LocalTime) {
return DateTimeFormatter.ISO_LOCAL_TIME;
} else if (temporal instanceof ZonedDateTime) {
return DateTimeFormatter.ISO_ZONED_DATE_TIME;
} else if (temporal instanceof OffsetDateTime) {
return DateTimeFormatter.ISO_OFFSET_DATE_TIME;
} else if (temporal instanceof Instant) {
return DateTimeFormatter.ISO_INSTANT;
}
return DateTimeFormatter.ISO_DATE_TIME;
}

/*
* Add array to buffer
*/
protected void array(Iterator it, Method method) throws JSONException {
protected void array(Iterator<?> it, Method method) throws JSONException {
this.add("[");

boolean hasData = false;
Expand Down Expand Up @@ -670,13 +706,13 @@ public void setEnumAsBean(boolean enumAsBean) {
@Override
public void setDateFormatter(String defaultDateFormat) {
if (defaultDateFormat != null) {
this.formatter = new SimpleDateFormat(defaultDateFormat);
this.dateFormat = new SimpleDateFormat(defaultDateFormat);
}
}

@Override
public void setCacheBeanInfo(boolean cacheBeanInfo) {
this.cacheBeanInfo = cacheBeanInfo;
// no-op
}

@Override
Expand All @@ -686,7 +722,7 @@ public void setExcludeProxyProperties(boolean excludeProxyProperties) {

protected static class JSONAnnotationFinder {
private boolean serialize = true;
private Method accessor;
private final Method accessor;
private String name;

public JSONAnnotationFinder(Method accessor) {
Expand All @@ -705,7 +741,7 @@ public String getName() {
public JSONAnnotationFinder invoke() {
JSON json = accessor.getAnnotation(JSON.class);
serialize = json.serialize();
if (serialize && json.name().length() > 0) {
if (serialize && !json.name().isEmpty()) {
name = json.name();
}
return this;
Expand Down
Loading
Loading