0

Not ZK dependend. But need help with Reflection method

asked 2011-07-20 09:04:01 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

updated 2011-07-20 09:31:31 +0800

Hi all,

i hope someone can help me with a code for a method for the following problem.

Apache beanUtils works with objects where the java.lang.Reflection works with Classes.

I have a working beanUtils method that gives me the value of a 'dot notation bean/property path' like this:

Object ob = getService().getManagerUser();
Object obj = PropertyUtils.getProperty(ob, "country.code2");
==> 'DE'


I need such a method that worked with a dotted path for classes with reflection.
It should gives me back the 'Field'. I mean that these should run with recursive calls.

Class<?> clazz = Class.forName("org.opentruuls.backend.user.model.ManagerUser");
String str = "country.code2";

Field field = getFieldFromDottedPath(clazz, str );

Pojos
public class ManagerUser {
. . .
private SystemCountry country;
private String name1;
. . .

public class SystemCountry {
. . .
@OT_LangPropertyKey("common.country.code2")
private String code2;
private String code3;
private String areaCode;
. . .

I need the 'Field' because for evaluating the Annotation;

Many many thanks for all help
Stephan

delete flag offensive retag edit

8 Replies

Sort by ยป oldest newest

answered 2011-07-20 12:09:23 +0800

marcelodecampos gravatar image marcelodecampos
183

Hi, Terry!!!!
I really want to help you because you're the man!!!!!
But I didn't undestand what do you need, and I'm very sorry, but could you explain a little bit better? :)

link publish delete flag offensive edit

answered 2011-07-20 15:43:48 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

updated 2011-07-20 15:46:39 +0800

Hi Marcel,

thanks for you and all who want to help me.

Ok, at time i'm evaluating a way to make a listbox with it's data a little bit dynamically. Means the user can select and save the columns who are be shown (dependend from a given starting class). Means, he can customize the list to render.

At this early stage i can load the listbox Field Definition from a database table, where i only store the starting full qualified className , fieldname and the order. This is runing very well in my DynamicItemRenderer. In this itemRenderer if data exists the used beanUtils method can give me a value from such a stored dot notated bean.bean.bean.property path like "address.country.code2" as you known if you are working with zk annotated databinding.

Object obj = org.apache.commons.beanutils.PropertyUtils.getProperty(startBeanObject, "address.country.code2");

String.ValueOf(obj) give i.e. the code2 field value. ( 'DE' or 'FR' or something other country code . ) BeanUtils works on Objects.
----------------------------
For labeling the Listheaders i need such a method with Reflection technique (working on Class MetaModels), because at ListHeaders creation time i haven't access to the data, so i haven't access to the created objects. I have only the store Field definition and with that i need a method for traversing through the dot notated Class.Class.Class.Property path to get the last property in the path as a type 'Field'.


needed method:

public Field getFieldFromDotNotatedPath(Class theStartlass, String  dotNotatedPropertyPath){

      // Starting class
      Class<?> startClass = ClassForName(theStartlass);

      // Go through the 'dotNotatedPropertyPath' and give back the last 'property' as field
      //  
     . . .
     . . .


      return thePropertyField;
}

method call:

String storedQualifiedClassName = "org.opentruuls.backend.user.model.Customer";
String dotNotatedPropertyPath = "address.country.code2";

Field field = getFieldFromDotNotatedPath(storedQualifiedClassName , dotNotatedPropertyPath );

Can be that there must be a second helper method for solving this.

Hope it's a little bit clearer.
Many many thanks
Stephan

link publish delete flag offensive edit

answered 2011-07-21 01:38:30 +0800

ashishd gravatar image ashishd flag of Taiwan
1972 6

Hi Stephan,
From a quick look in our source you can check out implementation of Fields#getByCompound(Object,String) and tweak it to not unwrap Field instance. If I have time i will try to do this but thought you might go ahead as well with this hint.

link publish delete flag offensive edit

answered 2011-07-21 04:37:31 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

Hi ashishd,

thanks for the hint. It's not the needed method.

The methods inner code must check and instantiate the founded substrings as clazz.newInstance() to become an object and go further the path to the last property.

thanks
Stephan

link publish delete flag offensive edit

answered 2011-07-21 05:05:31 +0800

ashishd gravatar image ashishd flag of Taiwan
1972 6

Hi Stephen,
If all you need is Field not the actual object instance then there should be no need to do class.newInstance(). Fields#getByCompound(Object,String) internally calls the get(Object,String) and here is its implementation from ZK source

	public static final Object get(Object obj, String name)
	throws NoSuchMethodException {
		try {
			final AccessibleObject acs = Classes.getAccessibleObject(
				obj.getClass(), name, null,
				Classes.B_GET|Classes.B_PUBLIC_ONLY);
			return 	acs instanceof Method ?
				((Method)acs).invoke(obj, null): ((Field)acs).get(obj); // do not unwrap the Field here instead return Field from here. Of course you need to change return type of this method
		} catch (NoSuchMethodException ex) {
			throw ex;
		} catch (Exception ex) {
			throw SystemException.Aide.wrap(ex, "Not found: " + name);
		}
	}

In above code see the return statement and the comment I added to understand what I meant.

link publish delete flag offensive edit

answered 2011-07-21 05:20:12 +0800

cyiannoulis gravatar image cyiannoulis
1201 10
Hi Stephen, We have implemented something like this to create dynamically columns in our lists. I have written a small snippet. Hope it will help you.
package snippets;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;

import com.web.framework.common.ReflectionTools;

public class FieldsAnalyzer {

	// Assume that the "base" class is the Person class. 
	private static String baseClassName = "snippets.Person";
	
	// The data source path 
	private static String dataSourcePath = "address.country.name";
	
	
	public static void main(String[] args) {

		/*
		 * Resolve the base class 
		 */
		Class baseClass = null;
		
		try {
			baseClass = Class.forName( baseClassName );
			System.out.println("Class resolved: " + baseClass.getName());
		} 
		catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
		/*
		 * Replace the dots in the data source path into something else to avoid problems with 'split' method.
		 */
		String datasource = dataSourcePath.replace('.', ':');
		/*
		 * Split data source path
		 */
		String dataSourceMembers[] = datasource.split(":");

		/*
		 * Initialize the clazz variable to the base class
		 */
		Class clazz = baseClass;
		
		/*
		 * Iterate the data source path and examine each data source path member
		 */
		for (int i=0; i<dataSourceMembers.length; i++) {
			
			String propertyName = dataSourceMembers<i >;

			/*
			 * We assume that each property has an associated getter
			 */
			Method getter = null;			
			getter = ReflectionTools.getGetterMethod(clazz, propertyName);

			/*
			 * Resolve the type of the property
			 */
			Class propertyClass = getter.getReturnType();
			
			/*
			 * If the property is a "real" data type, we assume that it is the last property 
			 * in the path and we can safely get the associated Field.  
			 */
			if (propertyClass.isAssignableFrom(String.class) 	||
				propertyClass.isAssignableFrom(Date.class) 		||
				propertyClass.isAssignableFrom(Integer.class) 	||
				propertyClass.isAssignableFrom(Short.class) 	||
				propertyClass.isAssignableFrom(Long.class) 		||
				propertyClass.isAssignableFrom(Float.class) 	||
				propertyClass.isAssignableFrom(Double.class) 	||
				propertyClass.isAssignableFrom(Character.class))
			{
					try {
						Field field = clazz.getDeclaredField( propertyName );
						System.out.println("Field resolved: " + field.getName());
					} 
					catch (SecurityException e) {
						e.printStackTrace();
					} 
					catch (NoSuchFieldException e) {
						e.printStackTrace();
					}
					
			}
			/*
			 * The property is something else, so resolve the class and continue.   
			 */
			else {
				try {
					clazz = Class.forName( propertyClass.getName() );
					System.out.println("Class resolved: " + clazz.getName());
				} 
				catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
			}
			
		}

	}
}

And here are the pojos:
package snippets;

public class Person {
	
	private String code;
	private String lastname;
	private Address address;
	
	public String getCode() {
		return code;
	}
	public void setCode(String code) {
		this.code = code;
	}
	public String getLastname() {
		return lastname;
	}
	public void setLastname(String lastname) {
		this.lastname = lastname;
	}
	public Address getAddress() {
		return address;
	}
	public void setAddress(Address address) {
		this.address = address;
	}

}

package snippets;

public class Address {

	private String address;
	private String zipcode;
	private Country country;
	
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getZipcode() {
		return zipcode;
	}
	public void setZipcode(String zipcode) {
		this.zipcode = zipcode;
	}
	public Country getCountry() {
		return country;
	}
	public void setCountry(Country country) {
		this.country = country;
	}
}

package snippets;

public class Country {

	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

/costas
link publish delete flag offensive edit

answered 2011-07-21 05:38:06 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

updated 2011-07-21 06:18:46 +0800

Hi costas and ashishd,

i have it :-)

I will check my code again and clean it from debugging stuff. I will post it today. Hope you can have a look on it. Many thanks for all help.

Stephan

link publish delete flag offensive edit

answered 2011-07-21 06:20:41 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

updated 2011-07-25 14:35:45 +0800

Thanks cyiannoulis too.

OK. Here is it

import java.lang.reflect.Field;

	/**
	 * EN: Get the field for the last string in a dot notation bean-property
	 * path. i.e. 'customer.address.country.code' = bean.bean.bean.property <br>
	 * DE: Ermittelt zum letzten String das zugehoerige Feld in einem Punkt
	 * notierten bean-property Pfad. <br>
	 * z.B. 'customer.address.country.code' = bean.bean.bean.property<br>
	 * 
	 * @param className
	 *            the className i.e. 'org.mypackage.Classname'
	 * @param propertyPath
	 *            begins with the first declared inner bean in ClassName
	 * @return the Field or null
	 */
	public static Field getFieldByPath(String className, String propertyPath) {

		Class<?> clazz;

		try {
			clazz = Class.forName(className);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			return null;
		}

		try {
			for (;;) {
				final int j = propertyPath.indexOf('.');

				// check is the last or only ONE String
				if (j < 0)
					return clazz.getDeclaredField(propertyPath);

				// if more than two Strings are separated with dot
				if (j > 0) {

					// get the first substring and try to instantiate
					// a class for them
					Field f = clazz.getDeclaredField(propertyPath.substring(0, j));

					// we check if this is not a primitive type or a 'real' data
					// type.
					if (!f.getType().isPrimitive() || 
                                                    !f.getType().isAssignableFrom(String.class) || 
                                                    !f.getType().isAssignableFrom(Date.class) || 
                                                    !f.getType().isAssignableFrom(Integer.class) || 
                                                    !f.getType().isAssignableFrom(Short.class) || 
                                                    !f.getType().isAssignableFrom(Long.class) || 
                                                    !f.getType().isAssignableFrom(Float.class) || 
                                                    !f.getType().isAssignableFrom(Double.class) || 
                                                    !f.getType().isAssignableFrom(Character.class))

							try {
								clazz = Class.forName(f.getType().getName());
							} catch (ClassNotFoundException e) {
								e.printStackTrace();
								return null;
							}
				}

				// cut the propertyPath for next loop
				propertyPath = propertyPath.substring(j + 1);
			}
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

best
Stephan

link publish delete flag offensive edit
Your reply
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!

[hide preview]

Question tools

Follow

RSS

Stats

Asked: 2011-07-20 09:04:01 +0800

Seen: 260 times

Last updated: Jul 21 '11

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More