com.feilong.lib.xstream.converters.reflection.FieldDictionary Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of feilong Show documentation
Show all versions of feilong Show documentation
feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.
/*
* Copyright (C) 2004, 2005, 2006 Joe Walnes.
* Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2018 XStream Committers.
* All rights reserved.
* The software in this package is published under the terms of the BSD
* style license a copy of which has been included with this distribution in
* the LICENSE.txt file.
* Created on 14. May 2004 by Joe Walnes
*/
package com.feilong.lib.xstream.converters.reflection;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import com.feilong.lib.xstream.core.Caching;
import com.feilong.lib.xstream.core.JVM;
import com.feilong.lib.xstream.core.util.OrderRetainingMap;
/**
* A field dictionary instance caches information about classes fields.
*
* @author Joe Walnes
* @author Jörg Schaible
* @author Guilherme Silveira
*/
public class FieldDictionary implements Caching{
private static final DictionaryEntry OBJECT_DICTIONARY_ENTRY = new DictionaryEntry(Collections.EMPTY_MAP, Collections.EMPTY_MAP);
private transient Map dictionaryEntries;
private transient FieldUtil fieldUtil;
private final FieldKeySorter sorter;
public FieldDictionary(){
this(new ImmutableFieldKeySorter());
}
public FieldDictionary(final FieldKeySorter sorter){
this.sorter = sorter;
init();
}
private void init(){
dictionaryEntries = new HashMap();
if (JVM.is15()){
try{
fieldUtil = (FieldUtil) JVM.loadClassForName("com.feilong.lib.xstream.converters.reflection.FieldUtil15", true)
.newInstance();
}catch (Exception e){
}
}
if (fieldUtil == null){
fieldUtil = new FieldUtil14();
}
}
/**
* Returns an iterator for all fields for some class
*
* @param cls
* the class you are interested on
* @return an iterator for its fields
*/
public Iterator fieldsFor(final Class cls){
return buildMap(cls, true).values().iterator();
}
/**
* Returns an specific field of some class. If definedIn is null, it searches for the field named 'name' inside the
* class cls. If definedIn is different than null, tries to find the specified field name in the specified class cls
* which should be defined in class definedIn (either equals cls or a one of it's superclasses)
*
* @param cls
* the class where the field is to be searched
* @param name
* the field name
* @param definedIn
* the superclass (or the class itself) of cls where the field was defined
* @return the field itself
* @throws ObjectAccessException
* if no field can be found
*/
public Field field(final Class cls,final String name,final Class definedIn){
final Field field = fieldOrNull(cls, name, definedIn);
if (field == null){
throw new MissingFieldException(cls.getName(), name);
}
return field;
}
/**
* Returns an specific field of some class. If definedIn is null, it searches for the field named 'name' inside the
* class cls. If definedIn is different than null, tries to find the specified field name in the specified class cls
* which should be defined in class definedIn (either equals cls or a one of it's superclasses)
*
* @param cls
* the class where the field is to be searched
* @param name
* the field name
* @param definedIn
* the superclass (or the class itself) of cls where the field was defined
* @return the field itself or null
* @since 1.4
*/
public Field fieldOrNull(final Class cls,final String name,final Class definedIn){
final Map fields = buildMap(cls, definedIn != null);
final Field field = (Field) fields.get(definedIn != null ? (Object) new FieldKey(name, definedIn, -1) : (Object) name);
return field;
}
private Map buildMap(final Class type,final boolean tupleKeyed){
Class cls = type;
DictionaryEntry lastDictionaryEntry = null;
final LinkedList superClasses = new LinkedList();
while (lastDictionaryEntry == null){
if (Object.class.equals(cls) || cls == null){
lastDictionaryEntry = OBJECT_DICTIONARY_ENTRY;
}else{
lastDictionaryEntry = getDictionaryEntry(cls);
}
if (lastDictionaryEntry == null){
superClasses.addFirst(cls);
cls = cls.getSuperclass();
}
}
for (final Iterator iter = superClasses.iterator(); iter.hasNext();){
cls = (Class) iter.next();
DictionaryEntry newDictionaryEntry = buildDictionaryEntryForClass(cls, lastDictionaryEntry);
synchronized (this){
final DictionaryEntry concurrentEntry = getDictionaryEntry(cls);
if (concurrentEntry == null){
dictionaryEntries.put(cls, newDictionaryEntry);
}else{
newDictionaryEntry = concurrentEntry;
}
}
lastDictionaryEntry = newDictionaryEntry;
}
return tupleKeyed ? lastDictionaryEntry.getKeyedByFieldKey() : lastDictionaryEntry.getKeyedByFieldName();
}
private DictionaryEntry buildDictionaryEntryForClass(final Class cls,final DictionaryEntry lastDictionaryEntry){
final Map keyedByFieldName = new HashMap(lastDictionaryEntry.getKeyedByFieldName());
final Map keyedByFieldKey = new OrderRetainingMap(lastDictionaryEntry.getKeyedByFieldKey());
final Field[] fields = cls.getDeclaredFields();
if (JVM.reverseFieldDefinition()){
for (int i = fields.length >> 1; i-- > 0;){
final int idx = fields.length - i - 1;
final Field field = fields[i];
fields[i] = fields[idx];
fields[idx] = field;
}
}
for (int i = 0; i < fields.length; i++){
final Field field = fields[i];
if (fieldUtil.isSynthetic(field) && field.getName().startsWith("$jacoco")){
continue;
}
if (!field.isAccessible()){
field.setAccessible(true);
}
final FieldKey fieldKey = new FieldKey(field.getName(), field.getDeclaringClass(), i);
final Field existent = (Field) keyedByFieldName.get(field.getName());
if (existent == null
// do overwrite statics
|| (existent.getModifiers() & Modifier.STATIC) != 0
// overwrite non-statics with non-statics only
|| (existent != null && (field.getModifiers() & Modifier.STATIC) == 0)){
keyedByFieldName.put(field.getName(), field);
}
keyedByFieldKey.put(fieldKey, field);
}
final Map sortedFieldKeys = sorter.sort(cls, keyedByFieldKey);
return new DictionaryEntry(keyedByFieldName, sortedFieldKeys);
}
private synchronized DictionaryEntry getDictionaryEntry(final Class cls){
return (DictionaryEntry) dictionaryEntries.get(cls);
}
@Override
public synchronized void flushCache(){
dictionaryEntries.clear();
if (sorter instanceof Caching){
((Caching) sorter).flushCache();
}
}
protected Object readResolve(){
init();
return this;
}
interface FieldUtil{
boolean isSynthetic(Field field);
}
private static final class DictionaryEntry{
private final Map keyedByFieldName;
private final Map keyedByFieldKey;
public DictionaryEntry(final Map keyedByFieldName, final Map keyedByFieldKey){
super();
this.keyedByFieldName = keyedByFieldName;
this.keyedByFieldKey = keyedByFieldKey;
}
public Map getKeyedByFieldName(){
return keyedByFieldName;
}
public Map getKeyedByFieldKey(){
return keyedByFieldKey;
}
}
}