mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-11 01:32:08 +10:00
refactor editably property
add transformer coil and core
This commit is contained in:
@@ -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...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user