You can use the class returned by Field getType method. See the example code bellow:
import java.lang.reflect.Field;
public class Main {
public static void main(String[] args) {
Field[] declaredFields = MyClass.class.getDeclaredFields();
for (Field declaredField : declaredFields) {
Class<?> fieldType = declaredField.getType();
String result=fieldType.getName();
System.out.println(result);
}
}
}
But be careful with primitive data types (example: boolean). In this case the fieldType.getName() function returns a uninstantiated string (boolean). You can handle it differently. The list of internal data types is here.
Answer from voji on Stack OverflowYou have to use isAssignableFrom.
The rather baroquely-named Class.isAssignableFrom is what you're after. I usually end up having to read the javadoc to make sure I get it the right way around:
Determines if the class or interface represented by this Class object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified Class parameter. It returns true if so; otherwise it returns false. If this Class object represents a primitive type, this method returns true if the specified Class parameter is exactly this Class object; otherwise it returns false.
Specifically, this method tests whether the type represented by the specified Class parameter can be converted to the type represented by this Class object via an identity conversion or via a widening reference conversion.
For example:
Copypublic class X {
public int i;
public static void main(String[] args) throws Exception {
Class<?> myType = Integer.class;
Object o = new X();
for (Field field : o.getClass().getFields()) {
if (field.getType().isAssignableFrom(myType)) {
System.out.println("Field " + field + " is assignable from type " + o.getClass());
}
}
}
}
Use reflection to access the fields declared on the class. Then iterate through the fields and check to see if their type matches Image.
You could also create a more useful method by accepting two parameters a target Class and a searchType Class. The method would then searches for fields with the target of the type searchType.
I would also recommend making this method static, since it really doesn't depend on any of the classes state.
Example
public class Contact {
private String surname, lastname, address;
private int age, floor;
private Image contactPhoto, companyPhoto;
private boolean isEmployed;
public static String[] getFieldsOfType(Class<?> target, Class<?> searchType) {
Field[] fields = target.getDeclaredFields();
List<String> results = new LinkedList<String>();
for(Field f:fields){
if(f.getType().equals(searchType)){
results.add(f.getName());
}
}
return results.toArray(new String[results.size()]);
}
public static String[] getAllImages(){
return getFieldsOfType(Contact.class, Image.class);
}
public static void main(String[] args) {
String[] fieldNames = getAllImages();
for(String name:fieldNames){
System.out.println(name);
}
}
}
A simpler alternative to using reflection would be to use a map as the primary data type for the field you are interested in:
public class Contact {
private static final String CONTACT_PHOTO = "contactPhoto";
private static final String COMPANY_PHOTO = "companyPhoto";
private String surname, lastname, address;
private int age, floor;
private HashMap<String, Image> images;
private boolean isEmployed;
public Contact() {
images = new HashMap<String, Image>();
images.put(CONTACT_PHOTO, null);
images.put(COMPANY_PHOTO, null);
}
public String[] getAllImages() {
Set<String> imageNames = images.keySet();
return imageNames.toArray(new String[imageNames.size()]);
}
public void setContactPhoto(Image img) {
images.put(CONTACT_PHOTO, img);
}
public Image getContactPhoto() {
return images.get(CONTACT_PHOTO);
}
public void setCompanyPhoto(Image img) {
images.put(COMPANY_PHOTO, img);
}
public Image getCompanyPhoto() {
return images.get(COMPANY_PHOTO);
}
}
Have a look at Obtaining Field Types from the Java Tutorial Trail: The Reflection API.
Basically, what you need to do is to get all java.lang.reflect.Field of your class and call Field#getType() on each of them (check edit below). To get all object fields including public, protected, package and private access fields, simply use Class.getDeclaredFields(). Something like this:
for (Field field : Person.class.getDeclaredFields()) {
System.out.format("Type: %s%n", field.getType());
System.out.format("GenericType: %s%n", field.getGenericType());
}
EDIT: As pointed out by wowest in a comment, you actually need to call Field#getGenericType(), check if the returned Type is a ParameterizedType and then grab the parameters accordingly. Use ParameterizedType#getRawType() and ParameterizedType#getActualTypeArgument() to get the raw type and an array of the types argument of a ParameterizedType respectively. The following code demonstrates this:
for (Field field : Person.class.getDeclaredFields()) {
System.out.print("Field: " + field.getName() + " - ");
Type type = field.getGenericType();
if (type instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType)type;
System.out.print("Raw type: " + pType.getRawType() + " - ");
System.out.println("Type args: " + pType.getActualTypeArguments()[0]);
} else {
System.out.println("Type: " + field.getType());
}
}
And would output:
Field: name - Type: class java.lang.String
Field: children - Raw type: interface java.util.List - Type args: class foo.Person
I haven't found any framework who determines a generic field type through the inheritance layers so i've written some method:
This logic determines the type through the field information and the current object class.
Listing 1 - logic:
public static Class<?> determineType(Field field, Object object) {
Class<?> type = object.getClass();
return (Class<?>) getType(type, field).type;
}
protected static class TypeInfo {
Type type;
Type name;
public TypeInfo(Type type, Type name) {
this.type = type;
this.name = name;
}
}
private static TypeInfo getType(Class<?> clazz, Field field) {
TypeInfo type = new TypeInfo(null, null);
if (field.getGenericType() instanceof TypeVariable<?>) {
TypeVariable<?> genericTyp = (TypeVariable<?>) field.getGenericType();
Class<?> superClazz = clazz.getSuperclass();
if (clazz.getGenericSuperclass() instanceof ParameterizedType) {
ParameterizedType paramType = (ParameterizedType) clazz.getGenericSuperclass();
TypeVariable<?>[] superTypeParameters = superClazz.getTypeParameters();
if (!Object.class.equals(paramType)) {
if (field.getDeclaringClass().equals(superClazz)) {
// this is the root class an starting point for this search
type.name = genericTyp;
type.type = null;
} else {
type = getType(superClazz, field);
}
}
if (type.type == null || type.type instanceof TypeVariable<?>) {
// lookup if type is not found or type needs a lookup in current concrete class
for (int j = 0; j < superClazz.getTypeParameters().length; ++j) {
TypeVariable<?> superTypeParam = superTypeParameters[j];
if (type.name.equals(superTypeParam)) {
type.type = paramType.getActualTypeArguments()[j];
Type[] typeParameters = clazz.getTypeParameters();
if (typeParameters.length > 0) {
for (Type typeParam : typeParameters) {
TypeVariable<?> objectOfComparison = superTypeParam;
if(type.type instanceof TypeVariable<?>) {
objectOfComparison = (TypeVariable<?>)type.type;
}
if (objectOfComparison.getName().equals(((TypeVariable<?>) typeParam).getName())) {
type.name = typeParam;
break;
}
}
}
break;
}
}
}
}
} else {
type.type = field.getGenericType();
}
return type;
}
Listing 2 - Samples / Tests:
class GenericSuperClass<E, T, A> {
T t;
E e;
A a;
BigDecimal b;
}
class GenericDefinition extends GenericSuperClass<Integer, Integer, Integer> {
}
@Test
public void testSimpleInheritanceTypeDetermination() {
GenericDefinition gd = new GenericDefinition();
Field field = ReflectionUtils.getField(gd, "t");
Class<?> clazz = ReflectionUtils.determineType(field, gd);
Assert.assertEquals(clazz, Integer.class);
field = ReflectionUtils.getField(gd, "b");
clazz = ReflectionUtils.determineType(field, gd);
Assert.assertEquals(clazz, BigDecimal.class);
}
class MiddleClass<A, E> extends GenericSuperClass<E, Integer, A> { }
// T = Integer, E = String, A = Double
class SimpleTopClass extends MiddleClass<Double, String> { }
@Test
public void testSimple2StageInheritanceTypeDetermination() {
SimpleTopClass stc = new SimpleTopClass();
Field field = ReflectionUtils.getField(stc, "t");
Class<?> clazz = ReflectionUtils.determineType(field, stc);
Assert.assertEquals(clazz, Integer.class);
field = ReflectionUtils.getField(stc, "e");
clazz = ReflectionUtils.determineType(field, stc);
Assert.assertEquals(clazz, String.class);
field = ReflectionUtils.getField(stc, "a");
clazz = ReflectionUtils.determineType(field, stc);
Assert.assertEquals(clazz, Double.class);
}
class TopMiddleClass<A> extends MiddleClass<A, Double> { }
// T = Integer, E = Double, A = Float
class ComplexTopClass extends TopMiddleClass<Float> {}
@Test void testComplexInheritanceTypDetermination() {
ComplexTopClass ctc = new ComplexTopClass();
Field field = ReflectionUtils.getField(ctc, "t");
Class<?> clazz = ReflectionUtils.determineType(field, ctc);
Assert.assertEquals(clazz, Integer.class);
field = ReflectionUtils.getField(ctc, "e");
clazz = ReflectionUtils.determineType(field, ctc);
Assert.assertEquals(clazz, Double.class);
field = ReflectionUtils.getField(ctc, "a");
clazz = ReflectionUtils.determineType(field, ctc);
Assert.assertEquals(clazz, Float.class);
}
class ConfusingClass<A, E> extends MiddleClass<E, A> {}
// T = Integer, E = Double, A = Float ; this class should map between a and e
class TopConfusingClass extends ConfusingClass<Double, Float> {}
@Test
public void testConfusingNamingConvetionWithInheritance() {
TopConfusingClass tcc = new TopConfusingClass();
Field field = ReflectionUtils.getField(tcc, "t");
Class<?> clazz = ReflectionUtils.determineType(field, tcc);
Assert.assertEquals(clazz, Integer.class);
field = ReflectionUtils.getField(tcc, "e");
clazz = ReflectionUtils.determineType(field, tcc);
Assert.assertEquals(clazz, Double.class);
field = ReflectionUtils.getField(tcc, "a");
clazz = ReflectionUtils.determineType(field, tcc);
Assert.assertEquals(clazz, Float.class);
field = ReflectionUtils.getField(tcc, "b");
clazz = ReflectionUtils.determineType(field, tcc);
Assert.assertEquals(clazz, BigDecimal.class);
}
class Pojo {
Byte z;
}
@Test
public void testPojoDetermineType() {
Pojo pojo = new Pojo();
Field field = ReflectionUtils.getField(pojo, "z");
Class<?> clazz = ReflectionUtils.determineType(field, pojo);
Assert.assertEquals(clazz, Byte.class);
}
I'm looking forward to hear your feedback!
Yes, you can. But since the type of obj is an anonymous class extending java.lang.Object, you can't reference its fields (type and value) directly, only via reflection.
Here's the code how you could do it:
String type = (String) obj.getClass().getDeclaredField("type").get(obj);
Object value = obj.getClass().getDeclaredField("value").get(obj);
// Type can be anything, so in order to instantiate it,
// we have to assume something. We assume it has a constructor
// which takes only a String value.
Object recreated = Class.forName(type).getConstructor(String.class)
.newInstance(value == null ? null : value.toString());
System.out.println(recreated);
Just have a look at new updated code :
Object obj = new Object() {
final String type = "java.lang.Integer";
final Object value = 6;
};
public void demo(){
try {
Field typeField = obj.getClass().getDeclaredField("type");
typeField.setAccessible(true);
String type = typeField.get(obj).toString();
Field valueField = obj.getClass().getDeclaredField("value");
valueField.setAccessible(true);
String value = valueField.get(obj).toString();
Class intClass = Class.forName(type);
Constructor intCons = intClass.getConstructor(String.class);
Integer i = (Integer) intCons.newInstance(value.toString());
System.out.println(i);
} catch (Exception e) {
e.printStackTrace();
}
}
Note : got help from this question.
UPDATE: Now getting the type and value from Object obj.