Goal: typesafe PropertyChanged events, minimum effort implementation for PropertyChanged events, runtime reflection of properties.
Am I reinventing the wheel or have I created something worthwile? Would you use it in your next project?
public interface StaticProperty {
public boolean canGet(); /** assert canGet()] */
public boolean canSet();
public boolean isvalid(); /** return rules().areAllMet() */
public boolean supportsPersistence(); /** assert instanceof Serializable && new T() */
public boolean canReturnNull(); /** assert canReturnNull && this.property != null */
public boolean canSetToNull(); /** assert canSetToNull() && value != null */
public boolean firesEvent();
public abstract class AbstractProperty
implements
StaticProperty {
protected boolean canGet = false; /** All false by default: explicitly set true in base */
protected boolean canGetNull = false;
protected boolean canSet = false;
protected boolean canSetNull = false;
protected boolean isValid = false;
protected boolean firesEvent = false;
protected boolean supportsPersistence;
protected AbstractProperty() {}
@Override public boolean canSet() {
return canSet;
}
@Override public boolean canSetToNull() {
return canSetNull;
}
@Override public boolean canReturnNull() {
return canGetNull;
}
@Override public boolean firesEvent() {
return firesEvent;
}
@Override public boolean isvalid() {
return isValid;
}
@Override public boolean canGet() {
return canGet;
}
@Override public boolean supportsPersistence() {
return supportsPersistence;
}
}
}
public class Props {
/**
* Any class having either getters, setters, or both
* With this, you can do:
*
* for (Property property : someObject.properties()) {
* query.select(property.name())
* .from(someObject.name());
* }
*
* */
public interface HasProperties {
public PropertyTypeList properties();
}
public interface IsChild<H extends HasSetters> {
public void doSet(H hasProperty); /** Dispatch setting to the property itself */
}
/**
* A readonly property
* */
public interface HasGetters extends HasProperties {
public IsChild getProp(StaticProperty type);
}
public interface FakeProperty extends HasGetters {
}
/** Write only property */
public interface HasSetters extends HasProperties {
public void setProp(StaticProperty type, IsChild value);
}
/** Because each property needs a dispatch method set(HasProperty parent), simple value types
* must be wrapped. */
public interface Value {
public interface StringValue extends Value {
public String value();
}
public interface IntValue extends Value {
public int value();
}
public interface DoubleValue extends Value {
public double value();
}
public interface DateValue extends Value {
public java.util.Date value();
}
public interface MultiValue extends Value {
public interface ValueList extends ImmutableList<Value> {}
public ValueList value();
}
}
public interface Handler<P extends IsChild> {
public void changed(P newProp, P oldProp);
public interface Handle {
public void remove();
}
}
public interface NotifiesPropertyChange {
// Type-safe property handling
public void addHandler(StaticProperty type, Handler handler);
// Register handling of any property change
public void addHandler(Handler handler);
}
/** Keeps track of property values, fires events, dispatches to property */
public static interface PropertyList
extends
ImmutableList<StaticProperty> {
public <H extends HasSetters, P extends IsChild> void set(StaticProperty type, P value, H hasProp);
public IsChild get(StaticProperty type);
public <H extends HasSetters, P extends IsChild> void setWithoutDispatch(StaticProperty type, P value, H hasProp);
public PropertyTypeList types();
public void addHandler(StaticProperty type, Handler handler);
public void addHandler(Handler handler);
public static class PropertyTypeList
extends
ImmutableListImpl<StaticProperty> {
public PropertyTypeList(List<StaticProperty> properties) {
super(properties);
}
public PropertyTypeList(StaticProperty... properties) {
super(properties);
}
@Override public String toString() {
return "PropertyTypeList [items=" + items + "]";
}
}
public static class Impl
extends
AbstractImmutableList<StaticProperty>
implements
PropertyList {
private final static boolean doDispatch = true;
private final static boolean ignoreDispatch = false;
private List<StaticProperty> types = new ArrayList<StaticProperty>();
private Map<StaticProperty, IsChild> properties = new HashMap<StaticProperty, IsChild>();
private Map<Class, List<Handler>> handlers = new HashMap<Class, List<Handler>>();
private List<Handler> geenricHandlers = new ArrayList<Handler>();
/** Construct from a list of property types */
public Impl(PropertyTypeList items2) {
for (StaticProperty p : items2) {
properties.put(p, null);
types.add(p);
}
}
/** Returns all the registered property types */
public PropertyTypeList types() {
return new PropertyTypeList(types);
}
@Override protected List<StaticProperty> createList() {
return new ArrayList<StaticProperty>();
}
/** Asserts given property is present and returns it */
public IsChild get(StaticProperty type) {
assert properties.containsKey(type);
return properties.get(type);
}
/** Asserts given type is present and sets the property, dispatching to the property */
@Override public <H extends HasSetters, P extends IsChild>
void set(StaticProperty type, P value, H hasProp) {
assert properties.containsKey(type.getClass());
doSet(type, value, hasProp, doDispatch);
}
/** Sets target property _without_ dispatching to the property */
@Override public <H extends HasSetters, P extends IsChild>
void setWithoutDispatch(StaticProperty type, P value, H hasProp) {
doSet(type, value, hasProp, ignoreDispatch);
}
/** Sets the new value, dispatches to property and fires event */
private <H extends HasSetters, P extends IsChild<H>>
void doSet(StaticProperty type, P value, H hasProp, boolean setParent) {
assert value != null && type.canSetToNull();
properties.put(type, value);
if (setParent)
value.doSet(hasProp);
if (type.firesEvent())
onChanged(type, value, null);
}
/** Adds handler for target property */
@Override public void addHandler(StaticProperty type, Handler handler) {
if (!handlers.containsKey(type.getClass()))
handlers.put(type.getClass(), new ArrayList<Handler>());
handlers.get(type.getClass()).add(handler);
}
/** Adds handler for any property change event */
public void addHandler(Handler handler) {
geenricHandlers.add(handler);
}
/** Fires event for target property and generic event */
public <P extends IsChild> void onChanged(StaticProperty type, P p, P old) {
List<Handler> handlersForType = handlers.get(type.getClass());
if (handlersForType != null)
for (Handler handler : handlersForType)
handler.changed(p, old);
for (Handler hanlder : geenricHandlers)
hanlder.changed(p, old);
}
}
}
}
public interface Woei
extends
HasName, SetsName,
HasDescription, SetsDescription,
NotifiesPropertyChange {
public static WoeiName nameP = new WoeiName();
public static WoeiDescription descriptionP = new WoeiDescription();
/** Extend properties and set rule values after calling the super constructor */
public static class WoeiName extends AbstractProperty {
public WoeiName() {
canSetNull = false;
firesEvent = true;
isValid = true;
canGetNull = true;
}
}
public static class WoeiDescription extends AbstractProperty {
public WoeiDescription() {
canSetNull = false;
firesEvent = true;
isValid = true;
canGetNull = true;
}
}
public static class WoeiImpl
implements Woei {
private static PropertyTypeList propertyTypes = new PropertyTypeList(nameP, descriptionP);
private PropertyList properties = new PropertyList.Impl(propertyTypes);
private Name name;
private Description description;
@Override public IsChild getProp(StaticProperty type) {
return properties.get(type);
}
@Override public PropertyTypeList properties() {
return properties.types();
}
@Override public Name name() {
return name;
}
@Override public void setName(Name name) {
this.name = name;
properties.setWithoutDispatch(nameP, name, this);
}
@Override public void setProp(StaticProperty type, IsChild value) {
properties.set(type, value, this);
}
@Override public Description description() {
return description;
}
@Override public void setDescription(Description description) {
this.description = description;
properties.setWithoutDispatch(descriptionP, description, this);
}
@Override public void addHandler(StaticProperty type, Handler handler) {
properties.addHandler(type, handler);
}
@Override public void addHandler(Handler handler) {
properties.addHandler(handler);
}
}
}
canReturnNull
andcanSetNull
. Why not a singlepermitsNull
or so? \$\endgroup\$ – Landei Oct 21 '11 at 9:34