/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.build;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import org.jnode.vm.classmgr.VmField;
import org.jnode.vm.classmgr.VmType;
/**
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
public final class FieldInfo {
/**
* All declared fields in the JDK type.
*/
@SuppressWarnings("unused")
private final Field[] jdkFields;
/**
* All declared instance fields that are a one-to-one map.
*/
private final Field[] jdkInstanceFields;
/**
* All declared statics fields that are a one-to-one map.
*/
private final Field[] jdkStaticFields;
/**
* All declared instance fields in the jnode type.
*/
private final List<VmField> jnodeInstanceFields;
/**
* All declared static fields in the jnode type.
*/
private final List<VmField> jnodeStaticFields;
private boolean exact = true;
/**
* Initialize this instance.
*
* @param jdkType
* @param jnodeType
*/
public FieldInfo(Class<?> jdkType, VmType<?> jnodeType) {
this.jdkFields = jdkType.getDeclaredFields();
this.jnodeInstanceFields = getInstanceFields(jnodeType);
this.jnodeStaticFields = getStaticFields(jnodeType);
this.jdkInstanceFields = toJdkFields(jdkType, jnodeInstanceFields);
this.jdkStaticFields = toJdkFields(jdkType, jnodeStaticFields);
}
/**
* Is this class an exact match between JDK & JNode type.
*/
public boolean isExact() {
return exact;
}
/**
* Return all declared instance fields that have a one-to-one map between JDK type and JNode type.
*
* @return Array of fields, certain offset may contain null.
*/
public Field[] getJdkInstanceFields() {
return jdkInstanceFields;
}
/**
* Return all declared static fields that have a one-to-one map between JDK type and JNode type.
*
* @return Array of fields, certain offset may contain null.
*/
public Field[] getJdkStaticFields() {
return jdkStaticFields;
}
/**
* Gets a declared jnode instance field at a given index.
*
* @param index
*/
public VmField getJNodeInstanceField(int index) {
return jnodeInstanceFields.get(index);
}
/**
* Gets a declared jnode static field at a given index.
*
* @param index
*/
public VmField getJNodeStaticField(int index) {
return jnodeStaticFields.get(index);
}
/**
* Convert a list of jnode fields into an array of one-to-one mapped
* jdk fields.
*
* @param jdkType
* @param jnodeFields
*/
private final Field[] toJdkFields(Class<?> jdkType, List<VmField> jnodeFields) {
final int cnt = jnodeFields.size();
final Field[] jdkFields = new Field[cnt];
for (int i = 0; i < cnt; i++) {
final VmField f = jnodeFields.get(i);
try {
jdkFields[i] = jdkType.getDeclaredField(f.getName());
jdkFields[i].setAccessible(true);
final boolean jdkStatic = ((jdkFields[i].getModifiers() & Modifier.STATIC) != 0);
if (f.isStatic() != jdkStatic) {
jdkFields[i] = null;
exact = false;
}
} catch (SecurityException ex) {
if (!f.isTransient()) {
exact = false;
}
// Ignore
} catch (NoSuchFieldException ex) {
if (!f.isTransient()) {
exact = false;
}
// Ignore
}
}
return jdkFields;
}
/**
* Gets the number of static fields declared in the given type.
*
* @param jnodeType
*/
private static List<VmField> getStaticFields(VmType<?> jnodeType) {
if (jnodeType != null) {
final int all = jnodeType.getNoDeclaredFields();
final ArrayList<VmField> list = new ArrayList<VmField>(all);
for (int i = 0; i < all; i++) {
final VmField f = jnodeType.getDeclaredField(i);
if (f.isStatic()) {
list.add(f);
}
}
return list;
} else {
return new ArrayList<VmField>(0);
}
}
/**
* Gets the number of instance fields declared in the given type.
*
* @param jnodeType
*/
private static List<VmField> getInstanceFields(VmType<?> jnodeType) {
if (jnodeType != null) {
final int all = jnodeType.getNoDeclaredFields();
final ArrayList<VmField> list = new ArrayList<VmField>(all);
for (int i = 0; i < all; i++) {
final VmField f = jnodeType.getDeclaredField(i);
if (!f.isStatic()) {
list.add(f);
}
}
return list;
} else {
return new ArrayList<VmField>(0);
}
}
}