package br.com.caelum.iogi.reflection; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import net.vidageek.mirror.dsl.Mirror; import net.vidageek.mirror.list.dsl.Matcher; import br.com.caelum.iogi.Instantiator; import br.com.caelum.iogi.parameters.Parameters; public class NewObject { public static NewObject nullNewObject() { return new NewObject(null, null, null) { @Override public Object value() { return null; } @Override public Object valueWithPropertiesSet() { return null; } }; } private final Instantiator<?> propertiesInstantiator; private final Parameters parameters; private final Object object; public NewObject(final Instantiator<?> propertiesInstantiator, final Parameters parameters, final Object newObjectValue) { this.propertiesInstantiator = propertiesInstantiator; this.parameters = parameters; this.object = newObjectValue; } public Object valueWithPropertiesSet() { populateProperties(); return value(); } public Object value() { return object; } private void populateProperties() { for (final Setter setter : Setter.settersIn(object)) { setProperty(setter); } } private void setProperty(final Setter setter) { if (parameters.hasRelatedTo(setter.asTarget())) { final Object propertyValue = propertiesInstantiator.instantiate(setter.asTarget(), parameters); setter.set(propertyValue); } } private static abstract class Setter { private static Collection<Setter> settersIn(final Object object) { final ArrayList<Setter> setters = new ArrayList<Setter>(); for (final Method setterMethod: JavaSetter.settersOf(object)) { setters.add(new JavaSetter(setterMethod, object)); } for (final Method setterMethod: ScalaSetter.settersOf(object)) { setters.add(new ScalaSetter(setterMethod, object)); } return Collections.unmodifiableList(setters); } protected final Method setter; private final Object object; public Setter(final Method setter, final Object object) { this.setter = setter; this.object = object; } public void set(final Object argument) { new Mirror().on(object).invoke().method(setter).withArgs(argument); } private Target<Object> asTarget() { return new Target<Object>(type(), propertyName()); } protected abstract String propertyName(); private Type type() { return setter.getGenericParameterTypes()[0]; } @Override public String toString() { return "Setter(" + propertyName() +")"; } } private static class JavaSetter extends Setter { public JavaSetter(Method setter, Object object) { super(setter, object); } @Override protected String propertyName() { final String capitalizedPropertyName = setter.getName().substring(3); final String propertyName = capitalizedPropertyName.substring(0, 1).toLowerCase() + capitalizedPropertyName.substring(1); return propertyName; } static List<Method> settersOf(Object object) { return new Mirror().on(object.getClass()).reflectAll().methods().matching(new Matcher<Method>() { public boolean accepts(final Method method) { return !method.isBridge() && !method.isSynthetic() && !Modifier.isAbstract(method.getModifiers()) && method.getParameterTypes().length == 1 && method.getName().startsWith("set"); } }); } } private static class ScalaSetter extends Setter { public ScalaSetter(Method setter, Object object) { super(setter, object); } @Override protected String propertyName() { return setter.getName().replace("_$eq", ""); } static List<Method> settersOf(Object object) { return new Mirror().on(object.getClass()).reflectAll().methods().matching(new Matcher<Method>() { public boolean accepts(final Method method) { return method.getName().endsWith("_$eq"); } }); } } }