refactor editably property

add transformer coil and core
This commit is contained in:
Branislav Stojkovic
2016-11-06 23:42:48 +01:00
parent dff7860002
commit 744e6a2576
22 changed files with 554 additions and 84 deletions
@@ -4,7 +4,6 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.diylc.core.IPropertyValidator;
import org.diylc.core.annotations.EditableProperty;
/**
* Entity class for editable properties extracted from component objects. Represents a single
@@ -23,12 +22,11 @@ public class PropertyWrapper implements Cloneable {
private IPropertyValidator validator;
private boolean unique = true;
private boolean changed = false;
private String additionalOptions;
private int sortOrder;
private Object[] listItems;
private Object ownerObject;
public PropertyWrapper(String name, Class<?> type, String getter, String setter, boolean defaultable,
IPropertyValidator validator, String additionalOptions, int sortOrder) {
IPropertyValidator validator, int sortOrder) {
super();
this.name = name;
this.type = type;
@@ -36,18 +34,14 @@ public class PropertyWrapper implements Cloneable {
this.setter = setter;
this.defaultable = defaultable;
this.validator = validator;
this.additionalOptions = additionalOptions;
this.sortOrder = sortOrder;
this.ownerObject = null;
}
public void readFrom(Object object) throws IllegalArgumentException, IllegalAccessException,
InvocationTargetException, SecurityException, NoSuchMethodException {
this.value = object.getClass().getMethod(getter).invoke(object);
if (additionalOptions.startsWith(EditableProperty.DYNAMIC_LIST)) {
String functionName = additionalOptions.substring(EditableProperty.DYNAMIC_LIST.length());
Method listMethod = object.getClass().getMethod(functionName);
listItems = (Object[]) listMethod.invoke(object);
}
this.ownerObject = object;
this.value = getGetter().invoke(object);
}
// public void readUniqueFrom(IDIYComponent component)
@@ -64,6 +58,10 @@ public class PropertyWrapper implements Cloneable {
object.getClass().getMethod(setter, type).invoke(object, this.value);
}
public Method getGetter() throws SecurityException, NoSuchMethodException {
return getOwnerObject().getClass().getMethod(getter);
}
public String getName() {
return name;
}
@@ -80,6 +78,10 @@ public class PropertyWrapper implements Cloneable {
this.value = value;
}
public Object getOwnerObject() {
return ownerObject;
}
public boolean isDefaultable() {
return defaultable;
}
@@ -104,22 +106,10 @@ public class PropertyWrapper implements Cloneable {
this.changed = changed;
}
public String getAdditionalOptions() {
return additionalOptions;
}
public int getSortOrder() {
return sortOrder;
}
public Object[] getListItems() {
return listItems;
}
public void setOptions(Object[] listItems) {
this.listItems = listItems;
}
// @Override
// public Object clone() throws CloneNotSupportedException {
// // Try to invoke clone method on value if possible.
@@ -134,7 +124,7 @@ public class PropertyWrapper implements Cloneable {
public Object clone() throws CloneNotSupportedException {
PropertyWrapper clone =
new PropertyWrapper(this.name, this.type, this.getter, this.setter, this.defaultable, this.validator,
this.additionalOptions, this.sortOrder);
this.sortOrder);
clone.value = this.value;
clone.changed = this.changed;
clone.unique = this.unique;
@@ -145,7 +135,6 @@ public class PropertyWrapper implements Cloneable {
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((additionalOptions == null) ? 0 : additionalOptions.hashCode());
result = prime * result + (defaultable ? 1231 : 1237);
result = prime * result + ((getter == null) ? 0 : getter.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
@@ -162,11 +151,6 @@ public class PropertyWrapper implements Cloneable {
if (getClass() != obj.getClass())
return false;
PropertyWrapper other = (PropertyWrapper) obj;
if (additionalOptions == null) {
if (other.additionalOptions != null)
return false;
} else if (!additionalOptions.equals(other.additionalOptions))
return false;
if (defaultable != other.defaultable)
return false;
if (getter == null) {
@@ -11,6 +11,7 @@ import java.util.Set;
import org.diylc.appframework.update.VersionNumber;
import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.annotations.MultiLineText;
import org.diylc.core.annotations.PositiveMeasureValidator;
import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit;
@@ -72,7 +73,8 @@ public class Project implements Serializable {
this.author = author;
}
@EditableProperty(defaultable = false, additionalOptions = EditableProperty.MULTI_LINE, sortOrder = 2)
@MultiLineText
@EditableProperty(defaultable = false, sortOrder = 2)
public String getDescription() {
return description;
}
@@ -0,0 +1,54 @@
package org.diylc.core.annotations;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public final class Defaults {
private Defaults() {}
private static final Map<Class<?>, Object> DEFAULTS;
static {
// Only add to this map via put(Map, Class<T>, T)
Map<Class<?>, Object> map = new HashMap<Class<?>, Object>();
put(map, boolean.class, false);
put(map, Boolean.class, false);
put(map, char.class, '\0');
put(map, byte.class, (byte) 0);
put(map, Byte.class, (byte) 0);
put(map, short.class, (short) 0);
put(map, Short.class, (short) 0);
put(map, int.class, 0);
put(map, Integer.class, 0);
put(map, long.class, 0L);
put(map, Long.class, 0L);
put(map, float.class, 0f);
put(map, Float.class, 0f);
put(map, double.class, 0d);
put(map, Double.class, 0d);
DEFAULTS = Collections.unmodifiableMap(map);
}
private static <T> void put(Map<Class<?>, Object> map, Class<T> type, T value) {
map.put(type, value);
}
/**
* Returns the default value of {@code type} as defined by JLS --- {@code 0} for numbers,
* {@code false} for {@code boolean} and {@code '\0'} for {@code char}. For non-primitive types
* and {@code void}, {@code null} is returned.
*
* @throws Exception
*/
@SuppressWarnings("unchecked")
public static <T> T defaultValue(Class<T> type) throws Exception {
// Primitives.wrap(type).cast(...) would avoid the warning, but we can't use that from here
// the put method enforces this key-value relationship
T t = (T) DEFAULTS.get(type);
if (t == null) {
return (T) type.getConstructors()[0].newInstance();
}
return t;
}
}
@@ -0,0 +1,10 @@
package org.diylc.core.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface DynamicList {
public String availableValueFunction();
}
@@ -33,18 +33,6 @@ import org.diylc.core.IPropertyValidator;
@Retention(RetentionPolicy.RUNTIME)
public @interface EditableProperty {
/**
* Used to designate that a {@link String} property can have multi-lined text.
*/
public static final String MULTI_LINE = "MULTI-LINE";
/**
* Used when property can have one of the values from a dynamic list. In such cases,
* {@link EditableProperty#additionalOptions()} should begin with
* {@link EditableProperty#DYNAMIC_LIST} and contain a method name from the parent object that
* should be called to obtain the {@link String} array with possible options.
*/
public static final String DYNAMIC_LIST = "DYNAMIC_LIST:";
/**
* Returns property name. If left blank property name will be extracted from the getter name, e.g.
* getter <code>getXYZ</code> will induce property name <code>XYZ</code>. <br>
@@ -75,12 +63,4 @@ public @interface EditableProperty {
* @return
*/
int sortOrder() default Integer.MAX_VALUE;
/**
* Optional parameter for properties that require additional configuration. This will be passed
* down to the editor factory.
*
* @return
*/
String additionalOptions() default "";
}
@@ -0,0 +1,6 @@
package org.diylc.core.annotations;
public @interface ElementLabel {
public String functionName();
}
@@ -0,0 +1,9 @@
package org.diylc.core.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface MultiLineText {
}
@@ -2,7 +2,9 @@ package org.diylc.plugins.cloud.model;
import java.io.Serializable;
import org.diylc.core.annotations.DynamicList;
import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.annotations.MultiLineText;
/**
* Represents a cloud project object, identified by {@link ProjectEntity#id}.
@@ -49,7 +51,8 @@ public class ProjectEntity implements Serializable {
this.name = name;
}
@EditableProperty(defaultable = false, additionalOptions = EditableProperty.MULTI_LINE, sortOrder = 3)
@MultiLineText
@EditableProperty(defaultable = false, sortOrder = 3)
public String getDescription() {
return description;
}
@@ -74,8 +77,8 @@ public class ProjectEntity implements Serializable {
this.category = category;
}
@EditableProperty(defaultable = false, sortOrder = 2, additionalOptions = EditableProperty.DYNAMIC_LIST
+ "getCategories")
@DynamicList(availableValueFunction="getCategories")
@EditableProperty(defaultable = false, sortOrder = 2)
public String getCategoryForDisplay() {
return categoryForDisplay;
}
@@ -139,26 +139,26 @@ public class ComponentProcessor {
return cloneProperties(propertyCache.get(clazz.getName()));
}
List<PropertyWrapper> properties = new ArrayList<PropertyWrapper>();
for (Method method : clazz.getMethods()) {
if (method.getName().startsWith("get")) {
for (Method getter : clazz.getMethods()) {
if (getter.getName().startsWith("get")) {
try {
if (method.isAnnotationPresent(EditableProperty.class) && !method.isAnnotationPresent(Deprecated.class)) {
EditableProperty annotation = method.getAnnotation(EditableProperty.class);
if (getter.isAnnotationPresent(EditableProperty.class) && !getter.isAnnotationPresent(Deprecated.class)) {
EditableProperty annotation = getter.getAnnotation(EditableProperty.class);
String name;
if (annotation.name().equals("")) {
name = method.getName().substring(3);
name = getter.getName().substring(3);
} else {
name = annotation.name();
}
IPropertyValidator validator = getPropertyValidator(annotation.validatorClass());
Method setter = clazz.getMethod("set" + method.getName().substring(3), method.getReturnType());
IPropertyValidator validator = getPropertyValidator(annotation.validatorClass());
Method setter = clazz.getMethod("set" + getter.getName().substring(3), getter.getReturnType());
PropertyWrapper property =
new PropertyWrapper(name, method.getReturnType(), method.getName(), setter.getName(),
annotation.defaultable(), validator, annotation.additionalOptions(), annotation.sortOrder());
new PropertyWrapper(name, getter.getReturnType(), getter.getName(), setter.getName(),
annotation.defaultable(), validator, annotation.sortOrder());
properties.add(property);
}
} catch (NoSuchMethodException e) {
LOG.debug("No matching setter found for \"" + method.getName() + "\". Skipping...");
LOG.debug("No matching setter found for \"" + getter.getName() + "\". Skipping...");
}
}
}