Strona główna > Java > Simplify in use anonymous class

Simplify in use anonymous class

It is a further explanation of idea, which I have described in reply to this.
I have created few classes that help me to write less code related with anonymous classes.

An example:

public class ComparatorTest {

    static Comparator myComparator; // 1

    // 2
    static int myComparator(Object o1, Object o2) {
        return (o1.toString().length() - o2.toString().length());
    }

    public static void main(String[] args) {
        // 3
        AnonymousClassCreator.createStaticObjectForAllFields(ComparatorTest.class);
        List<String> list = new ArrayList<String>();
        list.add("aaaa");
        list.add("cc");
        list.add("b");

        Collections.sort(list, myComparator); // 4

        System.out.println(list);
    }
}

In 3 objects are initiated in all possible static fields (in this example only one). It uses reflection and convention, that method and field with the same name are linked. In this example in filed 1 is created object that implement interface Comparator which use method 2. Further in 4 there is no null.

Implementation
Main class is AnonymousClassCreator :

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

public class AnonymousClassCreator {

	private static Map<Class, Creator> knownClass = new HashMap<Class, Creator>();

	static {
		ComparatorImpl.registerCreator();
		// FunctionImpl.registerCreator();
	}

	public static void createObjectForAllFields(Object target) {
		Field[] declaredFields = target.getClass().getDeclaredFields();
		for (Field field : declaredFields) {
			Class<?> type = field.getType();
			if (knownClass.keySet().contains(type)) {
				String expectedMethodName = field.getName();
				setField(field, target,
						createObjectForMethod(target, type, expectedMethodName));
			}
		}
	}

	public static void createStaticObjectForAllFields(Class targetClass) {
		Field[] declaredFields = targetClass.getDeclaredFields();
		for (Field field : declaredFields) {
			if (Modifier.isStatic(field.getModifiers())) {
				Class<?> type = field.getType();
				if (knownClass.keySet().contains(type)) {
					String expectedMethodName = field.getName();
					setField(field, null,
							createStaticObjectForMethod(targetClass, type,
							expectedMethodName));
				}
			}
		}
	}

	@SuppressWarnings("unchecked")
	public static <T> T createObjectForMethod(Object target, Class createObjectClass,
			String methodName) {
		return (T) getCreator(createObjectClass)
			.create(target,getMethod(target.getClass(), methodName));
	}

	@SuppressWarnings("unchecked")
	public static <T> T createStaticObjectForMethod(Class targetClass,
			Class createObjectClass, String methodName) {
		Method method = getMethod(targetClass, methodName);
		if (!Modifier.isStatic(method.getModifiers())) {
			throw new RuntimeException(
					"Can not create static anonymous class for not static method : "
					+ methodName + " ; typ : "
					+ createObjectClass + " in " + targetClass);
		}
		return (T) getCreator(createObjectClass).create(null, method);
	}

	private static Creator getCreator(Class clazz) {
		return knownClass.get(clazz);
	}

	private static void setField(Field field, Object object, Object value) {
		try {
			field.setAccessible(true);
			field.set(object, value);
			field.setAccessible(false);
		} catch (Exception e) {
			throw new RuntimeException("Exception in setField; field name '"
					+ field.getName() + "' in '" + object.getClass()
					+ "' value '" + value + "'", e);
		}
	}

	private static Method getMethod(Class<?> clazz, String methodName) {
		try {
			Method[] methods = clazz.getDeclaredMethods();
			for (Method method : methods) {
				if (method.getName().equals(methodName)) {
					return method;
				}
			}
		} catch (SecurityException e) {
			throw new RuntimeException("Excepton in getMethod : "
					+ methodName + " not found in " + clazz, e);
		}
		throw new RuntimeException("Method : " + methodName + " not found in " + clazz);
	}

	static Object execute(Object target, Method method, Object[] args) {
		try {
			method.setAccessible(true);
			return method.invoke(target, args);
		} catch (Exception e) {
			throw new RuntimeException("Exception in execution method : "
					+ method.getName()+ "  in "
					+ ((target != null) ? target.getClass() : null), e);
		}
	}

	protected static void registerCreator(Class clazz, Creator creator) {
		knownClass.put(clazz, creator);
	}

}

It also uses one interface Creator and base class BaseAnonymousClass.

import java.lang.reflect.Method;

public interface Creator {
    Object create(Object target, Method method);
}
import java.lang.reflect.Method;

public class BaseAnonymousClass {
    
    Object target;
    Method method;

    protected BaseAnonymousClass(Object target, Method method) {
        super();
        this.target = target;
        this.method = method;
    }
    
    protected static void registerCreator(Class type, Creator creator) {
        AnonymousClassCreator.registerCreator(type, creator);
    }
    
    public static void registerCreator() {
        throw new RuntimeException("Method 'registerCreator' should be implemented.");
    }
    
    protected <T> Object _eval(T... t) {
        return AnonymousClassCreator.execute(target, method, t);
    }
    
}

ComparatorImpl is an implementation of Comparator, it is an extension of BaseAnonymousClass:

import java.lang.reflect.Method;
import java.util.Comparator;

public class ComparatorImpl extends BaseAnonymousClass implements Comparator {

    public static void registerCreator() {
        registerCreator(Comparator.class, new Creator() {
            public Object create(Object target, Method method) {
                return new ComparatorImpl(target, method);
            }
        });
    }

    private ComparatorImpl(Object target, Method method) {
        super(target, method);
    }

    @Override
    public int compare(Object o1, Object o2) {
        return (Integer) _eval(new Object[] { o1, o2 });
    }

}

Adding extension
FunctionImpl is an example how to write extension. It is an implements of interface Function:

public interface Function {

    <T> void eval(T... t);

    <T> void eval(T t);
}
public class FunctionImpl extends BaseAnonymousClass implements Function {

    public static void registerCreator() {
        registerCreator(Function.class, new Creator() {
            public Object create(Object target, Method method) {
                return new FunctionImpl(target, method);
            }
        });
    }

    private FunctionImpl(Object target, Method method) {
        super(target, method);
    }

    public <T> void eval(T t) {
        _eval(new Object[] { t });

    }

    public <T> void eval(T... t) {
        _eval(t);
    }
}

All relations to AnonymousClassCreator are hidden in base class. It uses methods: _eval to pass arguments and registerCreator to tell AnonymousClassCreator how to use new type. Last method must be executed in client code or added to AnonymousClassCreator.

Example:

public class FunctionTest {

	Function printIt;
	Function addPostfix;
	Function addDate;

	public FunctionTest() {
		FunctionImpl.registerCreator();
		AnonymousClassCreator.createObjectForAllFields(this);
	}

	public static void main(String[] args) {
		FunctionTest test = new FunctionTest();
		test.doIt();
	}

	public void doIt() {
		// read
		String[] tab = { "A", "B", "C" };
		foreach(tab, printIt);

		// update
		StringBuffer[] sb = { new StringBuffer("A"), 
				new StringBuffer("B"), new StringBuffer("C") };
		foreach(sb, addPostfix);
		for (StringBuffer item : sb) {
			addDate.eval(item, new Date());
		}
		foreach(sb, printIt);
	}

	private <T> void foreach(T[] tab, Function fn) {
		for (T item : tab) {
			fn.eval(item);
		}
	}

	private void addPostfix(StringBuffer sb) {
		sb.append(" postfix ");
	}

	private void addDate(StringBuffer sb, Date date) {
		sb.append(" date: ").append(date);
	}

	private void printIt(Object item) {
		System.out.println("printIt : " + item);
	}
}

In this example was used other method to create required (not static) objects. AnonymousClassCreator has also two other methods that create object by specified name, example:

printIt =  AnonymousClassCreator.createObjectForMethod(test, Function.class, "printIt");

Conclusion
It not only reduces code (or it moves it to other place) but writing in this way (method as object) give some advantage. It is more “closure” style as it was shown in second example, and code is easier to read.

About these ads
Kategorie:Java Tagi:
  1. Brak komentarzy.
  1. No trackbacks yet.

Dodaj komentarz

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

WordPress.com Logo

Komentujesz korzystając z konta WordPress.com. Log Out / Zmień )

Twitter picture

Komentujesz korzystając z konta Twitter. Log Out / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Log Out / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Log Out / Zmień )

Connecting to %s

Follow

Otrzymuj każdy nowy wpis na swoją skrzynkę e-mail.

%d bloggers like this: