[incubator.betterbeansbinding] 2 new revisions pushed by fabrizio...@tidalwave.it on 2010-02-04 22:18 GMT

11 views
Skip to first unread message

betterbea...@googlecode.com

unread,
Feb 4, 2010, 5:19:02 PM2/4/10
to betterbean...@googlegroups.com
2 new revisions:

Revision: b28bcc31e8
Author: pet...@peterl.marand.si
Date: Thu Aug 27 11:14:44 2009
Log: initial commit of experimantal betterbeansbinding-xproperty module
http://code.google.com/p/betterbeansbinding/source/detail?repo=incubator&r=b28bcc31e8

Revision: ed282b08cf
Author: 5er_levart
Date: Sat Aug 29 09:31:41 2009
Log: got rid of all strings as property names
http://code.google.com/p/betterbeansbinding/source/detail?repo=incubator&r=ed282b08cf

==============================================================================
Revision: b28bcc31e8
Author: pet...@peterl.marand.si
Date: Thu Aug 27 11:14:44 2009
Log: initial commit of experimantal betterbeansbinding-xproperty module
http://code.google.com/p/betterbeansbinding/source/detail?repo=incubator&r=b28bcc31e8

Added:
/XProperty/pom.xml
/XProperty/src/main/java/org/betterbeansbinding/util/ClassNameUtils.java
/XProperty/src/main/java/org/betterbeansbinding/util/NullSafeUtils.java

/XProperty/src/main/java/org/betterbeansbinding/util/javassist/ClassPoolClassLoader.java

/XProperty/src/main/java/org/betterbeansbinding/xproperty/ConstantProperty.java

/XProperty/src/main/java/org/betterbeansbinding/xproperty/DelegatingXProperty.java

/XProperty/src/main/java/org/betterbeansbinding/xproperty/ExpressionProperty.java
/XProperty/src/main/java/org/betterbeansbinding/xproperty/Property$.java

/XProperty/src/main/java/org/betterbeansbinding/xproperty/Property$Factory.java

/XProperty/src/main/java/org/betterbeansbinding/xproperty/PropertyValue.java
/XProperty/src/main/java/org/betterbeansbinding/xproperty/XProperty.java

/XProperty/src/main/java/org/betterbeansbinding/xproperty/XPropertyHelper.java

/XProperty/src/main/java/org/betterbeansbinding/xproperty/propertyFactory/ImplementationClassGenerationStrategy.java

/XProperty/src/main/java/org/betterbeansbinding/xproperty/propertyFactory/ImplementationClassNamingStrategy.java

/XProperty/src/main/java/org/betterbeansbinding/xproperty/propertyFactory/ImplementationMembersGenerationStrategy.java

/XProperty/src/main/java/org/betterbeansbinding/xproperty/propertyFactory/PropertyMethodNamingStrategy.java
/XProperty/src/test/java/org/betterbeansbinding/xproperty/AbstractBean.java
/XProperty/src/test/java/org/betterbeansbinding/xproperty/Address.java
/XProperty/src/test/java/org/betterbeansbinding/xproperty/Employee.java
/XProperty/src/test/java/org/betterbeansbinding/xproperty/Person.java
/XProperty/src/test/java/org/betterbeansbinding/xproperty/PropsTest.java

=======================================
--- /dev/null
+++ /XProperty/pom.xml Thu Aug 27 11:14:44 2009
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.betterbeansbinding</groupId>
+ <artifactId>betterbeansbinding-xproperty</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <name>Better Beans Binding Property Extensions</name>
+
+ <build>
+ <plugins>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ <encoding>UTF-8</encoding>
+ <showDeprecation>true</showDeprecation>
+ <showWarnings>true</showWarnings>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <configuration>
+ <encoding>UTF-8</encoding>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/*Test.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+
+ </plugins>
+ </build>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>it.tidalwave.betterbeansbinding</groupId>
+ <artifactId>betterbeansbinding-core</artifactId>
+ <version>1.3.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>javassist</groupId>
+ <artifactId>javassist</artifactId>
+ <version>3.10.0</version>
+ </dependency>
+
+ <!-- unit tests -->
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.4</version>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+</project>
=======================================
--- /dev/null
+++
/XProperty/src/main/java/org/betterbeansbinding/util/ClassNameUtils.java
Thu Aug 27 11:14:44 2009
@@ -0,0 +1,36 @@
+package org.betterbeansbinding.util;
+
+/**
+ * @author Peter Levart
+ */
+public class ClassNameUtils
+{
+ public static String getJavaSourceName(Class<?> clazz)
+ {
+ return appendJavaSourceName(new StringBuilder(), clazz).toString();
+ }
+
+ public static StringBuilder appendJavaSourceName(StringBuilder sb,
Class<?> clazz)
+ {
+ if (clazz.isPrimitive())
+ return sb.append(clazz.getName());
+
+ if (clazz.isArray())
+ return appendJavaSourceName(sb,
clazz.getComponentType()).append("[]");
+
+ if (clazz.isAnonymousClass())
+ throw new IllegalArgumentException("Can't get the name of an
anonymous class");
+
+ if (clazz.getEnclosingConstructor() != null)
+ throw new IllegalArgumentException("Can't get the name of a
constructor-local class");
+
+ if (clazz.getEnclosingMethod() != null)
+ throw new IllegalArgumentException("Can't get the name of a
method-local class");
+
+ Class<?> enclosingClass = clazz.getEnclosingClass();
+ if (enclosingClass != null)
+ return appendJavaSourceName(sb,
enclosingClass).append(".").append(clazz.getSimpleName());
+
+ return sb.append(clazz.getName());
+ }
+}
=======================================
--- /dev/null
+++ /XProperty/src/main/java/org/betterbeansbinding/util/NullSafeUtils.java
Thu Aug 27 11:14:44 2009
@@ -0,0 +1,12 @@
+package org.betterbeansbinding.util;
+
+/**
+ * @author Peter Levart
+ */
+public class NullSafeUtils
+{
+ public static boolean equal(Object o1, Object o2)
+ {
+ return o1 == o2 || o1 != null && o2 != null && o1.equals(o2);
+ }
+}
=======================================
--- /dev/null
+++
/XProperty/src/main/java/org/betterbeansbinding/util/javassist/ClassPoolClassLoader.java
Thu Aug 27 11:14:44 2009
@@ -0,0 +1,131 @@
+package org.betterbeansbinding.util.javassist;
+
+import javassist.ClassPool;
+import javassist.LoaderClassPath;
+
+import java.security.ProtectionDomain;
+
+/**
+ * A standard model (delegating to parent first) {@link ClassLoader} that
loads it's own classes from the supplied {@link ClassPool}.
+ *
+ * @author Peter Levart
+ */
+public class ClassPoolClassLoader extends ClassLoader
+{
+ public static ClassPoolClassLoader newInstanceWithBoundPool()
+ {
+ return new ClassPoolClassLoader(new ClassPool());
+ }
+
+ public static ClassPoolClassLoader
newInstanceWithBoundPool(ClassLoader parent)
+ {
+ ClassPool pool = new ClassPool();
+ ClassPoolClassLoader loader = new ClassPoolClassLoader(parent,
pool);
+ pool.insertClassPath(new LoaderClassPath(parent));
+ return loader;
+ }
+
+ private ClassPool classPool;
+ private ProtectionDomain domain;
+
+ /**
+ * Creates a new class loader using the <tt>ClassLoader</tt> returned
by
+ * the method {@link #getSystemClassLoader()
+ * <tt>getSystemClassLoader()</tt>} as the parent class loader,
<tt>classPool</tt> as
+ * {@link ClassPool} used to load bytecode from and <tt>null</tt> as
{@link ProtectionDomain} used to define loaded classes with.
+ *
+ * @param classPool a {@link ClassPool} used to load bytecode for
classes from
+ */
+ public ClassPoolClassLoader(ClassPool classPool)
+ {
+ this((ProtectionDomain) null, classPool);
+ }
+
+ /**
+ * Creates a new class loader using the <tt>ClassLoader</tt> returned
by
+ * the method {@link #getSystemClassLoader()
+ * <tt>getSystemClassLoader()</tt>} as the parent class loader,
<tt>classPool</tt> as
+ * {@link ClassPool} used to load bytecode from and <tt>domain</tt> as
{@link ProtectionDomain} used to define loaded classes with.
+ *
+ * @param domain {@link ProtectionDomain} used to define loaded
classes with
+ * @param classPool a {@link ClassPool} used to load bytecode for
classes from
+ */
+ public ClassPoolClassLoader(ProtectionDomain domain, ClassPool
classPool)
+ {
+ super();
+ if (classPool == null)
+ throw new NullPointerException("classPool");
+ this.classPool = classPool;
+ this.domain = domain;
+ }
+
+ /**
+ * Creates a new class loader using the <tt>parent</tt> as the parent
class loader, <tt>classPool</tt> as
+ * {@link ClassPool} used to load bytecode from and <tt>null</tt> as
{@link ProtectionDomain} used to define loaded classes with.
+ *
+ * @param parent a parent {@link ClassLoader}
+ * @param classPool a {@link ClassPool} used to load bytecode for
classes from
+ */
+ public ClassPoolClassLoader(ClassLoader parent, ClassPool classPool)
+ {
+ this(parent, null, classPool);
+ }
+
+ /**
+ * Creates a new class loader using the <tt>ClassLoader</tt> as the
parent class loader, <tt>classPool</tt> as
+ * {@link ClassPool} used to load bytecode from and <tt>domain</tt> as
{@link ProtectionDomain} used to define loaded classes with.
+ *
+ * @param parent a parent {@link ClassLoader}
+ * @param domain {@link ProtectionDomain} used to define loaded
classes with
+ * @param classPool a {@link ClassPool} used to load bytecode for
classes from
+ */
+ public ClassPoolClassLoader(ClassLoader parent, ProtectionDomain
domain, ClassPool classPool)
+ {
+ super(parent);
+ if (classPool == null)
+ throw new NullPointerException("classPool");
+ this.classPool = classPool;
+ this.domain = domain;
+ }
+
+ public ClassPool getClassPool()
+ {
+ return classPool;
+ }
+
+ protected Class findClass(String name) throws ClassNotFoundException
+ {
+ byte[] classfile;
+ try
+ {
+ classfile = classPool.get(name).toBytecode();
+ }
+ catch (Exception e)
+ {
+ throw new ClassNotFoundException(name, e);
+ }
+
+ int i = name.lastIndexOf('.');
+ if (i != -1)
+ {
+ String packageName = name.substring(0, i);
+ if (getPackage(packageName) == null)
+ try
+ {
+ definePackage(
+ packageName, null, null, null, null, null, null,
null
+ );
+ }
+ catch (IllegalArgumentException e)
+ {
+ // ignore. maybe the package object for the same
+ // name has been created just right away.
+ }
+ }
+
+ if (domain == null)
+ return defineClass(name, classfile, 0, classfile.length);
+ else
+ return defineClass(name, classfile, 0, classfile.length,
domain);
+ }
+}
=======================================
--- /dev/null
+++
/XProperty/src/main/java/org/betterbeansbinding/xproperty/ConstantProperty.java
Thu Aug 27 11:14:44 2009
@@ -0,0 +1,130 @@
+package org.betterbeansbinding.xproperty;
+
+import org.jdesktop.beansbinding.PropertyStateListener;
+
+/**
+ * @author Peter Levart
+ */
+public class ConstantProperty<S, V> extends XProperty<S, V>
+{
+ /**
+ * Creates an instance of {@code ConstantProperty}.
+ *
+ * @param value the value for new constant property
+ * @return the constant property for given value
+ */
+ public static <S, V> ConstantProperty<S, V> constant(V value)
+ {
+ return new ConstantProperty<S, V>(value);
+ }
+
+ private final V value;
+
+ private ConstantProperty(V value)
+ {
+ this.value = value;
+ }
+
+ /**
+ * Throws {@code UnsupportedOperationException}; {@code
ConstantProperty} is never writeable.
+ *
+ * @param source {@inheritDoc}
+ * @return never returns; always throws {@code
UnsupportedOperationException}; {@code ConstantProperty} is never writeable
+ * @throws UnsupportedOperationException always; {@code
ConstantProperty} is never writeable
+ * @see #isWriteable
+ */
+ public Class<? extends V> getWriteType(S source)
+ {
+ throw new UnsupportedOperationException("Unwriteable");
+ }
+
+ /**
+ * Returns the value of this constant property.
+ *
+ * @return the value of this constant property
+ * @see #isReadable
+ */
+ public V getValue(S source)
+ {
+ return value;
+ }
+
+ /**
+ * Throws {@code UnsupportedOperationException}; {@code
ConstantProperty} is never writeable.
+ *
+ * @param source {@inheritDoc}
+ * @throws UnsupportedOperationException always; {@code
ConstantProperty} is never writeable
+ * @see #isWriteable
+ * @see #getWriteType
+ */
+ public void setValue(S source, V value)
+ {
+ throw new UnsupportedOperationException("Unwriteable");
+ }
+
+ /**
+ * Returns {@code true}; {@code ConstantProperty} is always readable.
+ *
+ * @return {@code true}; {@code ObjectPropert} is always readable
+ * @see #isWriteable
+ */
+ public boolean isReadable(Object source)
+ {
+ return true;
+ }
+
+ /**
+ * Returns {@code false}; {@code ConstantProperty} is never writeable.
+ *
+ * @return {@code false}; {@code ConstantProperty} is never writeable
+ * @see #isReadable
+ */
+ public boolean isWriteable(Object source)
+ {
+ return false;
+ }
+
+ /**
+ * Returns a string representation of the {@code ConstantProperty}.
This
+ * method is intended to be used for debugging purposes only, and
+ * the content and format of the returned string may vary between
+ * implementations. The returned string may be empty but may not
+ * be {@code null}.
+ *
+ * @return a string representation of this {@code ConstantProperty}
+ */
+ public String toString()
+ {
+ return String.valueOf(value);
+ }
+
+ /**
+ * Does nothing; the state of an {@code ConstantProperty} never
changes so
+ * listeners aren't useful.
+ */
+ public void addPropertyStateListener(S source, PropertyStateListener
listener)
+ {
+ }
+
+ /**
+ * Does nothing; the state of an {@code ConstantProperty} never
changes so
+ * listeners aren't useful.
+ *
+ * @see #addPropertyStateListener
+ */
+ public void removePropertyStateListener(S source,
PropertyStateListener listener)
+ {
+ }
+
+ /**
+ * Returns an empty array; the state of an {@code ConstantProperty}
never changes
+ * so listeners aren't useful.
+ *
+ * @return an empty array
+ * @see #addPropertyStateListener
+ */
+ public PropertyStateListener[] getPropertyStateListeners(S source)
+ {
+ return new PropertyStateListener[0];
+ }
+}
=======================================
--- /dev/null
+++
/XProperty/src/main/java/org/betterbeansbinding/xproperty/DelegatingXProperty.java
Thu Aug 27 11:14:44 2009
@@ -0,0 +1,107 @@
+package org.betterbeansbinding.xproperty;
+
+import org.jdesktop.beansbinding.Property;
+import org.jdesktop.beansbinding.PropertyStateEvent;
+import org.jdesktop.beansbinding.PropertyStateListener;
+
+/**
+ * An {@link XProperty} implementation that delegates to another {@link
Property}
+ *
+ * @author Peter Levart
+ */
+public class DelegatingXProperty<S, V> extends XPropertyHelper<S, V>
+{
+ public static <S, V> XProperty<S, V> wrap(Property<S, V> property)
+ {
+ return new DelegatingXProperty<S, V>().init(property);
+ }
+
+ private Property<S, V> property;
+
+ protected DelegatingXProperty<S, V> init(Property<S, V> property)
+ {
+ if (this.property != null)
+ throw new IllegalStateException("This DelegatingXProperty is
already initialized");
+
+ if (property == null)
+ throw new NullPointerException("property should not be null");
+
+ this.property = property;
+
+ return this;
+ }
+
+ @Override
+ protected Property<S, V> property()
+ {
+ if (property == null)
+ throw new IllegalStateException("This DelegatingXProperty is
not initialized");
+
+ return property;
+ }
+
+ //
+ // delegation to real property implementation
+
+ public Class<? extends V> getWriteType(S source)
+ {
+ return property().getWriteType(source);
+ }
+
+ public V getValue(S source)
+ {
+ return property().getValue(source);
+ }
+
+ public void setValue(S source, V value)
+ {
+ property().setValue(source, value);
+ }
+
+ public boolean isReadable(S source)
+ {
+ return property().isReadable(source);
+ }
+
+ public boolean isWriteable(S source)
+ {
+ return property().isWriteable(source);
+ }
+
+ //
+ // registering for changes on the delegate
+
+ @Override
+ protected void listeningStarted(S source)
+ {
+ property().addPropertyStateListener(source, listener);
+ }
+
+ @Override
+ protected void listeningStopped(S source)
+ {
+ property().removePropertyStateListener(source, listener);
+ }
+
+ //
+ // dispatching delegate's PropertyStateEvents to our listeners
+
+ private final PropertyStateListener listener = new
PropertyStateListener()
+ {
+ @Override
+ public void propertyStateChanged(PropertyStateEvent pse)
+ {
+ firePropertyStateChange(
+ new PropertyStateEvent(
+ DelegatingXProperty.this, // IMPORTANT: pretend we are
the sourceProperty!
+ pse.getSourceObject(),
+ pse.getValueChanged(),
+ pse.getValueChanged() ? pse.getOldValue() : null,
+ pse.getValueChanged() ? pse.getNewValue() : null,
+ pse.getWriteableChanged(),
+ pse.getWriteableChanged() && pse.isWriteable()
+ )
+ );
+ }
+ };
+}
=======================================
--- /dev/null
+++
/XProperty/src/main/java/org/betterbeansbinding/xproperty/ExpressionProperty.java
Thu Aug 27 11:14:44 2009
@@ -0,0 +1,650 @@
+package org.betterbeansbinding.xproperty;
+
+import org.betterbeansbinding.util.NullSafeUtils;
+import org.jdesktop.beansbinding.Property;
+import org.jdesktop.beansbinding.PropertyStateEvent;
+import org.jdesktop.beansbinding.PropertyStateListener;
+
+import java.util.Collection;
+import java.util.Locale;
+import java.util.Iterator;
+
+/**
+ * Static factory methods for composing properties out of other properties
- building expressions
+ *
+ * @author Peter Levart
+ */
+public abstract class ExpressionProperty<S, SV, V> extends
XPropertyHelper<S, V>
+{
+ //
+ // static factory methods
+
+ public static <S> XProperty<S, Boolean> not(Property<S, Boolean>
property)
+ {
+ return new UnnaryOp<S, Boolean, Boolean>(property)
+ {
+ @Override
+ protected Boolean calculateValue(Boolean parameter) throws
Exception
+ {
+ return !parameter;
+ }
+ };
+ }
+
+ public static <S> XProperty<S, Boolean> and(Property<S, Boolean>...
properties)
+ {
+ return new ExpressionProperty<S, Boolean, Boolean>(properties)
+ {
+ @Override
+ protected Boolean calculateValue(Values parameters) throws
Exception
+ {
+ for (int i = 0; i < parameters.length(); i++)
+ if (!parameters.get(i))
+ return false;
+
+ return true;
+ }
+ };
+ }
+
+ public static <S> XProperty<S, Boolean> or(Property<S, Boolean>...
properties)
+ {
+ return new ExpressionProperty<S, Boolean, Boolean>(properties)
+ {
+ @Override
+ protected Boolean calculateValue(Values parameters) throws
Exception
+ {
+ for (int i = 0; i < parameters.length(); i++)
+ if (parameters.get(i))
+ return true;
+
+ return false;
+ }
+ };
+ }
+
+ public static <S> XProperty<S, Boolean> isNull(Property<S, ?> property)
+ {
+ return new UnnaryOp<S, Object, Boolean>(property)
+ {
+ @Override
+ protected Boolean calculateValue(Object parameter) throws
Exception
+ {
+ return parameter == null;
+ }
+ };
+ }
+
+ public static <S> XProperty<S, Boolean> isNotNull(Property<S, ?>
property)
+ {
+ return new UnnaryOp<S, Object, Boolean>(property)
+ {
+ @Override
+ protected Boolean calculateValue(Object parameter) throws
Exception
+ {
+ return parameter != null;
+ }
+ };
+ }
+
+ //
+ // comparisons
+
+ // property <=> value
+
+ public static <S, V extends Comparable<V>> XProperty<S, Boolean>
gt(Property<S, V> property, V value)
+ {
+ return new UnnaryCompare<S, V>(property, value)
+ {
+ @Override
+ protected boolean calculateValue(V parameter, V value) throws
Exception
+ {
+ return parameter.compareTo(value) > 0;
+ }
+ };
+ }
+
+ public static <S, V extends Comparable<V>> XProperty<S, Boolean>
ge(Property<S, V> property, V value)
+ {
+ return new UnnaryCompare<S, V>(property, value)
+ {
+ @Override
+ protected boolean calculateValue(V parameter, V value) throws
Exception
+ {
+ return parameter.compareTo(value) >= 0;
+ }
+ };
+ }
+
+ public static <S, V extends Comparable<V>> XProperty<S, Boolean>
lt(Property<S, V> property, V value)
+ {
+ return new UnnaryCompare<S, V>(property, value)
+ {
+ @Override
+ protected boolean calculateValue(V parameter, V value) throws
Exception
+ {
+ return parameter.compareTo(value) < 0;
+ }
+ };
+ }
+
+ public static <S, V extends Comparable<V>> XProperty<S, Boolean>
le(Property<S, V> property, V value)
+ {
+ return new UnnaryCompare<S, V>(property, value)
+ {
+ @Override
+ protected boolean calculateValue(V parameter, V value) throws
Exception
+ {
+ return parameter.compareTo(value) <= 0;
+ }
+ };
+ }
+
+ public static <S, V extends Comparable<V>> XProperty<S, Boolean>
eq(Property<S, V> property, V value)
+ {
+ return new UnnaryCompare<S, V>(property, value)
+ {
+ @Override
+ protected boolean calculateValue(V parameter, V value) throws
Exception
+ {
+ return parameter.compareTo(value) == 0;
+ }
+ };
+ }
+
+ // property1 <=> property2
+
+ public static <S, V extends Comparable<V>> XProperty<S, Boolean>
gt(Property<S, V> property1, Property<S, V> property2)
+ {
+ return new BinayOp<S, V, Boolean>(property1, property2)
+ {
+ @Override
+ protected Boolean calculateValue(V parameter1, V parameter2)
throws Exception
+ {
+ return parameter1.compareTo(parameter2) > 0;
+ }
+ };
+ }
+
+ public static <S, V extends Comparable<V>> XProperty<S, Boolean>
ge(Property<S, V> property1, Property<S, V> property2)
+ {
+ return new BinayOp<S, V, Boolean>(property1, property2)
+ {
+ @Override
+ protected Boolean calculateValue(V parameter1, V parameter2)
throws Exception
+ {
+ return parameter1.compareTo(parameter2) >= 0;
+ }
+ };
+ }
+
+ public static <S, V extends Comparable<V>> XProperty<S, Boolean>
lt(Property<S, V> property1, Property<S, V> property2)
+ {
+ return new BinayOp<S, V, Boolean>(property1, property2)
+ {
+ @Override
+ protected Boolean calculateValue(V parameter1, V parameter2)
throws Exception
+ {
+ return parameter1.compareTo(parameter2) < 0;
+ }
+ };
+ }
+
+ public static <S, V extends Comparable<V>> XProperty<S, Boolean>
le(Property<S, V> property1, Property<S, V> property2)
+ {
+ return new BinayOp<S, V, Boolean>(property1, property2)
+ {
+ @Override
+ protected Boolean calculateValue(V parameter1, V parameter2)
throws Exception
+ {
+ return parameter1.compareTo(parameter2) <= 0;
+ }
+ };
+ }
+
+ public static <S, V extends Comparable<V>> XProperty<S, Boolean>
eq(Property<S, V> property1, Property<S, V> property2)
+ {
+ return new BinayOp<S, V, Boolean>(property1, property2)
+ {
+ @Override
+ protected Boolean calculateValue(V parameter1, V parameter2)
throws Exception
+ {
+ return parameter1.compareTo(parameter2) == 0;
+ }
+ };
+ }
+
+ //
+ // null safe equality
+
+ public static <S> XProperty<S, Boolean> equal(Property<S, ?> property,
final Object value)
+ {
+ return new UnnaryOp<S, Object, Boolean>(property)
+ {
+ @Override
+ protected Boolean calculateValue(Object parameter) throws
Exception
+ {
+ return NullSafeUtils.equal(parameter, value);
+ }
+ };
+ }
+
+ public static <S> XProperty<S, Boolean> equal(Property<S, ?>
property1, Property<S, ?> property2)
+ {
+ return new BinayOp<S, Object, Boolean>(property1, property2)
+ {
+ @Override
+ protected Boolean calculateValue(Object parameter1, Object
parameter2) throws Exception
+ {
+ return NullSafeUtils.equal(parameter1, parameter2);
+ }
+ };
+ }
+
+ public static <S> XProperty<S, Boolean> notEqual(Property<S, ?>
property, final Object value)
+ {
+ return new UnnaryOp<S, Object, Boolean>(property)
+ {
+ @Override
+ protected Boolean calculateValue(Object parameter) throws
Exception
+ {
+ return !NullSafeUtils.equal(parameter, value);
+ }
+ };
+ }
+
+ public static <S> XProperty<S, Boolean> notEqual(Property<S, ?>
property1, Property<S, ?> property2)
+ {
+ return new BinayOp<S, Object, Boolean>(property1, property2)
+ {
+ @Override
+ protected Boolean calculateValue(Object parameter1, Object
parameter2) throws Exception
+ {
+ return !NullSafeUtils.equal(parameter1, parameter2);
+ }
+ };
+ }
+
+ //
+ // string expressions
+
+ public static <S> XProperty<S, String> join(Property<S, ? extends
CharSequence>... properties)
+ {
+ return join(null, properties);
+ }
+
+ public static <S> XProperty<S, String> join(final CharSequence
delimiter, Property<S, ? extends CharSequence>... properties)
+ {
+ return new ExpressionProperty<S, CharSequence, String>(properties)
+ {
+ @Override
+ protected String calculateValue(Values parameters) throws
Exception
+ {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < parameters.length(); i++)
+ {
+ if (delimiter != null && i > 0)
+ sb.append(delimiter);
+ sb.append(parameters.get(i));
+ }
+ return sb.toString();
+ }
+ };
+ }
+
+ public static <S> XProperty<S, String> format(final String format,
Property<S, ?>... properties)
+ {
+ return new ExpressionProperty<S, Object, String>(properties)
+ {
+ @Override
+ protected String calculateValue(Values parameters) throws
Exception
+ {
+ Object[] args = new Object[parameters.length()];
+ for (int i = 0; i < parameters.length(); i++)
+ args[i] = parameters.get(i);
+
+ return String.format(format, args);
+ }
+ };
+ }
+
+ public static <S> XProperty<S, String> format(final Locale locale,
final String format, Property<S, ?>... properties)
+ {
+ return new ExpressionProperty<S, Object, String>(properties)
+ {
+ @Override
+ protected String calculateValue(Values parameters) throws
Exception
+ {
+ Object[] args = new Object[parameters.length()];
+ for (int i = 0; i < parameters.length(); i++)
+ args[i] = parameters.get(i);
+
+ return String.format(locale, format, args);
+ }
+ };
+ }
+
+ //
+ // collections
+
+ public static <S, V extends Collection<?>> XProperty<S, Boolean>
isEmpty(Property<S, V> property)
+ {
+ return new UnnaryOp<S, V, Boolean>(property)
+ {
+ @Override
+ protected Boolean calculateValue(V parameter) throws Exception
+ {
+ return parameter == null || parameter.isEmpty();
+ }
+ };
+ }
+
+ public static <S, V extends Collection<?>> XProperty<S, Boolean>
isNotEmpty(Property<S, V> property)
+ {
+ return new UnnaryOp<S, V, Boolean>(property)
+ {
+ @Override
+ protected Boolean calculateValue(V parameter) throws Exception
+ {
+ return parameter != null && !parameter.isEmpty();
+ }
+ };
+ }
+
+ public static <S, V extends Collection<?>> XProperty<S, Integer>
size(Property<S, V> property)
+ {
+ return new UnnaryOp<S, V, Integer>(property)
+ {
+ @Override
+ protected Integer calculateValue(V parameter) throws Exception
+ {
+ return parameter.size();
+ }
+ };
+ }
+
+ public static <S, E, V extends Collection<E>> XProperty<S, E>
firstElement(Property<S, V> property)
+ {
+ return new UnnaryOp<S, V, E>(property)
+ {
+ @Override
+ protected E calculateValue(V parameter) throws Exception
+ {
+ Iterator<E> i = parameter.iterator();
+ return i.hasNext() ? i.next() : null;
+ }
+ };
+ }
+
+ public static <S, E, V extends Collection<E>> XProperty<S, E>
singleElement(Property<S, V> property)
+ {
+ return new UnnaryOp<S, V, E>(property)
+ {
+ @Override
+ protected E calculateValue(V parameter) throws Exception
+ {
+ Iterator<E> i = parameter.iterator();
+ E fistElement = i.hasNext() ? i.next() : null;
+ return i.hasNext() ? null : fistElement;
+ }
+ };
+ }
+
+ //
+ // tupples
+
+ public static <S> XProperty<S, Object[]> tupple(final
Property<S, ?> ... properties)
+ {
+ return new ExpressionProperty<S, Object, Object[]>(properties)
+ {
+ @Override protected Object[] calculateValue(Values parameters)
throws Exception
+ {
+ Object[] tupple = new Object[parameters.length()];
+ for (int i = 0; i < parameters.length(); i++)
+ tupple[i] = parameters.get(i);
+ return tupple;
+ }
+ };
+ }
+
+ //
+ // implementation
+
+ @Override
+ public Class<? extends V> getWriteType(S source)
+ {
+ throw new UnsupportedOperationException("Unwriteable");
+ }
+
+ private Property<S, ? extends SV>[] properties;
+
+ public ExpressionProperty(Property<S, ? extends SV>... properties)
+ {
+ this.properties = properties;
+ }
+
+ @Override
+ public V getValue(S source)
+ {
+ try
+ {
+ return calculateValue(new Values(source));
+ }
+ catch (UnsupportedOperationException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new UnsupportedOperationException("Unreadable", e);
+ }
+ }
+
+ @Override
+ public void setValue(S source, V value)
+ {
+ throw new UnsupportedOperationException("Unwriteable");
+ }
+
+ @Override
+ public boolean isReadable(S source)
+ {
+ try
+ {
+ calculateValue(new Values(source));
+ return true;
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean isWriteable(S source)
+ {
+ return false;
+ }
+
+ @Override
+ protected void listeningStarted(S source)
+ {
+ for (Property<S, ? extends SV> property : properties)
+ property.addPropertyStateListener(source, LISTENER);
+ }
+
+ @Override
+ protected void listeningStopped(S source)
+ {
+ for (Property<S, ? extends SV> property : properties)
+ property.removePropertyStateListener(source, LISTENER);
+ }
+
+ private final PropertyStateListener LISTENER = new
PropertyStateListener()
+ {
+ @Override
+ public void propertyStateChanged(PropertyStateEvent pse)
+ {
+ if (!pse.getValueChanged())
+ return;
+
+ Object source = pse.getSourceObject();
+ Property sourceProperty = pse.getSourceProperty();
+
+ Object oldValue = calculateValueOrUnreadable(new
Values(source, sourceProperty, pse.getOldValue()));
+ Object newValue = calculateValueOrUnreadable(new
Values(source, sourceProperty, pse.getNewValue()));
+
+ if (NullSafeUtils.equal(oldValue, newValue))
+ return;
+
+ firePropertyStateChange(
+ new PropertyStateEvent(
+ ExpressionProperty.this,
+ source,
+ true,
+ oldValue,
+ newValue,
+ false,
+ false
+ )
+ );
+ }
+ };
+
+ protected class Values
+ {
+ private S source;
+ private Property<S, ? extends SV> exceptProperty;
+ private SV exceptValue;
+
+ Values(S source)
+ {
+ this(source, null, null);
+ }
+
+ @SuppressWarnings({"unchecked"})
+ Values(Object source, Property exceptProperty, Object exceptValue)
+ {
+ this.source = (S) source;
+ this.exceptProperty = (Property<S, ? extends SV>)
exceptProperty;
+ this.exceptValue = (SV) exceptValue;
+ }
+
+ public int length()
+ {
+ return properties.length;
+ }
+
+ public SV get(int index)
+ {
+ Property<S, ? extends SV> property = properties[index];
+
+ if (property == exceptProperty)
+ {
+ if (exceptValue == PropertyStateEvent.UNREADABLE)
+ throw new Unreadable();
+
+ return exceptValue;
+ }
+ else
+ {
+ if (!property.isReadable(source))
+ throw new Unreadable();
+
+ return property.getValue(source);
+ }
+ }
+ }
+
+ protected static class Unreadable extends UnsupportedOperationException
+ {
+ private static final StackTraceElement[] EMPTY_STACK_TRACE = new
StackTraceElement[0];
+
+ public Unreadable()
+ {
+ super("Unreadabe");
+ setStackTrace(EMPTY_STACK_TRACE);
+ }
+
+ @Override
+ public Throwable fillInStackTrace()
+ {
+ return this;
+ }
+ }
+
+ private Object calculateValueOrUnreadable(Values parameters)
+ {
+ try
+ {
+ return calculateValue(parameters);
+ }
+ catch (Exception e)
+ {
+ return PropertyStateEvent.UNREADABLE;
+ }
+ }
+
+ /**
+ * @param parameters the parameters to use in calculation
+ * @return the calculated value
+ * @throws Exception if it can not calculate value
+ */
+ protected abstract V calculateValue(Values parameters) throws
Exception;
+
+ //
+ // specialized implementations or bases
+
+ public abstract static class UnnaryOp<S, SV, V> extends
ExpressionProperty<S, SV, V>
+ {
+ public UnnaryOp(Property<S, ? extends SV> property)
+ {
+ super(property);
+ }
+
+ @Override
+ protected final V calculateValue(Values parameters) throws
Exception
+ {
+ return calculateValue(parameters.get(0));
+ }
+
+ protected abstract V calculateValue(SV parameter) throws Exception;
+ }
+
+ public abstract static class UnnaryCompare<S, SV extends
Comparable<SV>> extends UnnaryOp<S, SV, Boolean>
+ {
+ private final SV value;
+
+ public UnnaryCompare(Property<S, ? extends SV> property, SV value)
+ {
+ super(property);
+ if (value == null)
+ throw new NullPointerException("value");
+ this.value = value;
+ }
+
+ @Override
+ protected final Boolean calculateValue(SV parameter) throws
Exception
+ {
+ return calculateValue(parameter, value);
+ }
+
+ protected abstract boolean calculateValue(SV parameter, SV value)
throws Exception;
+ }
+
+ public abstract static class BinayOp<S, SV, V> extends
ExpressionProperty<S, SV, V>
+ {
+ public BinayOp(Property<S, ? extends SV> property1, Property<S, ?
extends SV> property2)
+ {
+ super(property1, property2);
+ }
+
+ @Override
+ protected final V calculateValue(Values parameters) throws
Exception
+ {
+ return calculateValue(parameters.get(0), parameters.get(1));
+ }
+
+ protected abstract V calculateValue(SV parameter1, SV parameter2)
throws Exception;
+ }
+}
=======================================
--- /dev/null
+++
/XProperty/src/main/java/org/betterbeansbinding/xproperty/Property$.java
Thu Aug 27 11:14:44 2009
@@ -0,0 +1,39 @@
+package org.betterbeansbinding.xproperty;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * @author Peter Levart
+ */
+public class Property$<S, V> extends DelegatingXProperty<S, V>
+{
+ private final ConcurrentMap<String, Property$> subPropertiesCache =
new ConcurrentHashMap<String, Property$>();
+ private String propertyPath;
+
+ protected <V2, P$ extends Property$<S, V2>> P$ subProperty(Class<P$>
property$Class, String propertyName)
+ {
+ P$ subProperty =
property$Class.cast(subPropertiesCache.get(propertyName));
+
+ if (subProperty == null)
+ {
+ subProperty = Property$Factory.create(property$Class,
property(), propertyName);
+ Property$ oldSubProperty =
subPropertiesCache.putIfAbsent(propertyName, subProperty);
+ if (oldSubProperty != null)
+ subProperty = property$Class.cast(oldSubProperty);
+ }
+
+ subProperty.propertyPath = propertyPath == null ? propertyName :
propertyPath + "." + propertyName;
+
+ return subProperty;
+ }
+
+ /**
+ * @return the dot ('.') delimited path of individual BeanProperty
names leading to this property or null if this property
+ * represents an ObjectProperty.
+ */
+ public String getPropertyPath()
+ {
+ return propertyPath;
+ }
+}
=======================================
--- /dev/null
+++
/XProperty/src/main/java/org/betterbeansbinding/xproperty/Property$Factory.java
Thu Aug 27 11:14:44 2009
@@ -0,0 +1,122 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.betterbeansbinding.xproperty;
+
+import
org.betterbeansbinding.xproperty.propertyFactory.ImplementationClassGenerationStrategy;
+import
org.betterbeansbinding.xproperty.propertyFactory.ImplementationClassNamingStrategy;
+import
org.betterbeansbinding.xproperty.propertyFactory.ImplementationMembersGenerationStrategy;
+import
org.betterbeansbinding.xproperty.propertyFactory.PropertyMethodNamingStrategy;
+import org.jdesktop.beansbinding.BeanProperty;
+import org.jdesktop.beansbinding.ObjectProperty;
+import org.jdesktop.beansbinding.Property;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * @author peterl
+ */
+public class Property$Factory
+{
+ private static final Property$Factory INSTANCE = new Property$Factory(
+ ImplementationClassNamingStrategy.Impl.DEFAULT,
+ PropertyMethodNamingStrategy.Impl.DEFAULT,
+ ImplementationClassGenerationStrategy.Impl.JAVASSIST,
+ ImplementationMembersGenerationStrategy.Impl.DEFAULT
+ );
+
+ public static <B, P$ extends Property$<B, B>> P$ create(Class<P$>
property$Class)
+ {
+ return create(property$Class, null, null);
+ }
+
+ public static <S, B, V, P$ extends Property$<S, V>> P$
create(Class<P$> property$Class, Property<S, B> baseProperty, String
propertyName)
+ {
+ return INSTANCE.createProperty$(property$Class, baseProperty,
propertyName);
+ }
+
+ private Property$Factory(
+ ImplementationClassNamingStrategy
implementationClassNamingStrategy,
+ PropertyMethodNamingStrategy propertyMethodNamingStrategy,
+ ImplementationClassGenerationStrategy
implementationClassGenerationStrategy,
+ ImplementationMembersGenerationStrategy
implementationMembersGenerationStrategy
+ )
+ {
+ this.implementationClassNamingStrategy =
implementationClassNamingStrategy;
+ this.propertyMethodNamingStrategy = propertyMethodNamingStrategy;
+ this.implementationClassGenerationStrategy =
implementationClassGenerationStrategy;
+ this.implementationMembersGenerationStrategy =
implementationMembersGenerationStrategy;
+ }
+
+ private ImplementationClassNamingStrategy
implementationClassNamingStrategy;
+ private PropertyMethodNamingStrategy propertyMethodNamingStrategy;
+ private ImplementationClassGenerationStrategy
implementationClassGenerationStrategy;
+ private ImplementationMembersGenerationStrategy
implementationMembersGenerationStrategy;
+
+ @SuppressWarnings({"SynchronizationOnLocalVariableOrMethodParameter"})
+ public <S, B, V, P$ extends Property$<S, V>> P$
createProperty$(Class<P$> property$Class, Property<S, B> baseProperty,
String propertyName)
+ {
+ Class<? extends P$> implementationClass;
+ String implementationClassName =
implementationClassNamingStrategy.getImplementationClassName(property$Class);
+
+ synchronized (property$Class)
+ {
+ try
+ {
+ ClassLoader classLoader =
implementationClassGenerationStrategy.getImplementationClassLoader(property$Class);
+
+ implementationClass = classLoader
+ .loadClass(implementationClassName)
+ .asSubclass(property$Class);
+ }
+ catch (ClassNotFoundException e)
+ {
+ implementationClass =
implementationClassGenerationStrategy.createImplementationClass(
+ property$Class,
+ implementationClassName,
+ propertyMethodNamingStrategy,
+ implementationMembersGenerationStrategy
+ );
+ }
+ }
+
+ Constructor constructor;
+ try
+ {
+ constructor =
implementationClass.getConstructor(Property.class);
+ }
+ catch (NoSuchMethodException e)
+ {
+ throw new IllegalArgumentException("There should be a public
constructor taking Property parameter in class: " +
implementationClass.getName(), e);
+ }
+
+ Property<S, V> subProperty = subProperty(baseProperty,
propertyName);
+
+ try
+ {
+ return
property$Class.cast(constructor.newInstance(subProperty));
+ }
+ catch (InstantiationException e)
+ {
+ throw new IllegalArgumentException(e);
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new IllegalArgumentException(e);
+ }
+ catch (InvocationTargetException e)
+ {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ @SuppressWarnings({"unchecked"})
+ private <S, B, V> Property<S, V> subProperty(Property<S, B>
baseProperty, String propertyName)
+ {
+ return propertyName == null
+ ? (Property<S, V>) ObjectProperty.create()
+ : BeanProperty.<S, V>create(baseProperty, propertyName);
+ }
+}
=======================================
--- /dev/null
+++
/XProperty/src/main/java/org/betterbeansbinding/xproperty/PropertyValue.java
Thu Aug 27 11:14:44 2009
@@ -0,0 +1,154 @@
+package org.betterbeansbinding.xproperty;
+
+import org.jdesktop.beansbinding.AutoBinding;
+import org.jdesktop.beansbinding.Bindings;
+import org.jdesktop.beansbinding.Property;
+import org.jdesktop.beansbinding.PropertyStateListener;
+
+/**
+ * A combination of source object and a property
+ *
+ * @author Peter Levart
+ */
+public interface PropertyValue<SS, SV>
+{
+ //
+ // obtaining underlying source and property
+
+ SS getSource();
+
+ Property<SS, SV> getProperty();
+
+ //
+ // delegating to underlying property for underlying source
+
+ Class<? extends SV> getWriteType();
+
+ SV getValue();
+
+ void setValue(SV value);
+
+ boolean isReadable();
+
+ boolean isWriteable();
+
+ void addPropertyStateListener(PropertyStateListener listener);
+
+ void removePropertyStateListener(PropertyStateListener listener);
+
+ PropertyStateListener[] getPropertyStateListeners();
+
+ //
+ // binding
+
+ <TS, TV> AutoBinding<SS, SV, TS, TV> readWriteBind(PropertyValue<TS,
TV> propertyValue);
+
+ <TS, TV> AutoBinding<SS, SV, TS, TV> readBind(PropertyValue<TS, TV>
propertyValue);
+
+ <TS, TV> AutoBinding<SS, SV, TS, TV> readOnceBind(PropertyValue<TS,
TV> propertyValue);
+
+ <TS, TV> AutoBinding<SS, SV, TS, TV> bind(AutoBinding.UpdateStrategy
strategy, PropertyValue<TS, TV> propertyValue);
+
+ //
+ // Simple implementation
+
+ class Impl<SS, SV> implements PropertyValue<SS, SV>
+ {
+ private final SS source;
+ private final Property<SS, SV> property;
+
+ public Impl(SS source, Property<SS, SV> property)
+ {
+ this.source = source;
+ this.property = property;
+ }
+
+ @Override
+ public SS getSource()
+ {
+ return source;
+ }
+
+ @Override
+ public Property<SS, SV> getProperty()
+ {
+ return property;
+ }
+
+ @Override
+ public Class<? extends SV> getWriteType()
+ {
+ return property.getWriteType(source);
+ }
+
+ @Override
+ public SV getValue()
+ {
+ return property.getValue(source);
+ }
+
+ @Override
+ public void setValue(SV value)
+ {
+ property.setValue(source, value);
+ }
+
+ @Override
+ public boolean isReadable()
+ {
+ return property.isReadable(source);
+ }
+
+ @Override
+ public boolean isWriteable()
+ {
+ return property.isWriteable(source);
+ }
+
+ @Override
+ public void addPropertyStateListener(PropertyStateListener
listener)
+ {
+ property.addPropertyStateListener(source, listener);
+ }
+
+ @Override
+ public void removePropertyStateListener(PropertyStateListener
listener)
+ {
+ property.removePropertyStateListener(source, listener);
+ }
+
+ @Override
+ public PropertyStateListener[] getPropertyStateListeners()
+ {
+ return property.getPropertyStateListeners(source);
+ }
+
+ @Override
+ public <TS, TV> AutoBinding<SS, SV, TS, TV>
readWriteBind(PropertyValue<TS, TV> propertyValue)
+ {
+ return bind(AutoBinding.UpdateStrategy.READ_WRITE,
propertyValue);
+ }
+
+ @Override
+ public <TS, TV> AutoBinding<SS, SV, TS, TV>
readBind(PropertyValue<TS, TV> propertyValue)
+ {
+ return bind(AutoBinding.UpdateStrategy.READ, propertyValue);
+ }
+
+ @Override
+ public <TS, TV> AutoBinding<SS, SV, TS, TV>
readOnceBind(PropertyValue<TS, TV> propertyValue)
+ {
+ return bind(AutoBinding.UpdateStrategy.READ_ONCE,
propertyValue);
+ }
+
+ @Override
+ public <TS, TV> AutoBinding<SS, SV, TS, TV>
bind(AutoBinding.UpdateStrategy strategy, PropertyValue<TS, TV>
propertyValue)
+ {
+ AutoBinding<SS, SV, TS, TV> binding =
Bindings.createAutoBinding(
+ strategy, source, property, propertyValue.getSource(),
propertyValue.getProperty()
+ );
+ binding.bind();
+ return binding;
+ }
+ }
+}
=======================================
--- /dev/null
+++
/XProperty/src/main/java/org/betterbeansbinding/xproperty/XProperty.java
Thu Aug 27 11:14:44 2009
@@ -0,0 +1,44 @@
+package org.betterbeansbinding.xproperty;
+
+import org.jdesktop.beansbinding.Property;
+
+/**
+ * A {@link Property} base with some extension utility methods such as:
{@link #of}
+ *
+ * @author Peter Levart
+ */
+public abstract class XProperty<S, V> extends Property<S, V>
+{
+ /**
+ * Delegating subclasses can override this method to return delegate
Property which will be used instead of this instance
+ * for binding by methods of this class (for example: {@link #of})
+ *
+ * @return this instance
+ */
+ protected Property<S, V> property()
+ {
+ return this;
+ }
+
+ /**
+ * @param source the source object
+ * @return a {@link PropertyValue} representing a pair of property and
source object
+ */
+ public PropertyValue<S, V> of(S source)
+ {
+ return new PropertyValue.Impl<S, V>(source, property());
+ }
+
+ //
+ // Expressions
+
+ public XProperty<S, Boolean> isNull()
+ {
+ return ExpressionProperty.isNull(property());
+ }
+
+ public XProperty<S, Boolean> isNotNull()
+ {
+ return ExpressionProperty.isNotNull(property());
+ }
+}
=======================================
--- /dev/null
+++
/XProperty/src/main/java/org/betterbeansbinding/xproperty/XPropertyHelper.java
Thu Aug 27 11:14:44 2009
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2007 Sun Microsystems, Inc. All rights reserved. Use is
+ * subject to license terms.
+ */
+
+package org.betterbeansbinding.xproperty;
+
+import org.jdesktop.beansbinding.PropertyStateEvent;
+import org.jdesktop.beansbinding.PropertyStateListener;
+
+import java.util.ArrayList;
+import java.util.IdentityHashMap;
+import java.util.List;
+
+/**
+ * Note: this is a fork of {@link
org.jdesktop.beansbinding.PropertyHelper} with
+ * riped-off support for by-property-instance-listeners and relaxed
subclassability of
+ * {@link #addPropertyStateListener} and {@link
#removePropertyStateListener}
+ * methods (they are not final anymore).<p/>
+ * <p/>
+ * An abstract subclass of {@code XProperty} that helps with the
management of
+ * {@code PropertyStateListeners} by implementing the methods for adding,
removing,
+ * and getting listeners. {@code AbstractXProperty} is designed to manage
listeners
+ * for multiple source objects only.
+ * <p/>
+ * {@code AbstractXProperty} also provides, by way of the protected methods
+ * {@link #listeningStarted} and {@link #listeningStopped} a hook for
subclasses
+ * to know when it's time to start tracking changes to a particular source
object.
+ *
+ * @author Shannon Hickey
+ * @author Peter Levart (hacked the fork of {@link
org.jdesktop.beansbinding.PropertyHelper})
+ * @param <S> the type of source object that this {@code Property}
operates on
+ * @param <V> the type of value that this {@code Property} represents
+ */
+public abstract class XPropertyHelper<S, V> extends XProperty<S, V>
+{
+ private Object listeners;
+
+ private List<PropertyStateListener> getListeners(S source, boolean
create)
+ {
+ @SuppressWarnings({"unchecked"})
+ IdentityHashMap<S, List<PropertyStateListener>> map =
(IdentityHashMap<S, List<PropertyStateListener>>) listeners;
+
+ if (map == null)
+ {
+ if (create)
+ {
+ map = new IdentityHashMap<S,
List<PropertyStateListener>>();
+ listeners = map;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ List<PropertyStateListener> list = map.get(source);
+ if (list == null && create)
+ {
+ list = new ArrayList<PropertyStateListener>();
+ map.put(source, list);
+ }
+
+ return list;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws UnsupportedOperationException {@inheritDoc}
+ */
+ public abstract Class<? extends V> getWriteType(S source);
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws UnsupportedOperationException {@inheritDoc}
+ */
+ public abstract V getValue(S source);
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws UnsupportedOperationException {@inheritDoc}
+ */
+ public abstract void setValue(S source, V value);
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws UnsupportedOperationException {@inheritDoc}
+ */
+ public abstract boolean isReadable(S source);
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws UnsupportedOperationException {@inheritDoc}
+ */
+ public abstract boolean isWriteable(S source);
+
+ /**
+ * Called when this {@code AbstractXProperty} changes from having
+ * no listeners installed for the given source object to
+ * having listeners installed for the given source object. This
+ * is the ideal time for subclasses to install any listeners needed
+ * to track change on the source object.
+ *
+ * @see #listeningStopped
+ */
+ protected void listeningStarted(S source)
+ {
+ }
+
+ /**
+ * Called when this {@code AbstractXProperty} changes from having
+ * listeners installed for the given source object to
+ * having no listeners installed for the given source object. This
+ * is the ideal time for subclasses to remove any listeners that
+ * they've installed to track changes on the source object.
+ *
+ * @see #listeningStopped
+ */
+ protected void listeningStopped(S source)
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void addPropertyStateListener(S source, PropertyStateListener
listener)
+ {
+ if (listener == null)
+ {
+ return;
+ }
+
+ List<PropertyStateListener> listeners = getListeners(source, true);
+ boolean wasListening = (listeners.size() != 0);
+ listeners.add(listener);
+
+ if (!wasListening)
+ {
+ listeningStarted(source);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void removePropertyStateListener(S source,
PropertyStateListener listener)
+ {
+ if (listener == null)
+ {
+ return;
+ }
+
+ List<PropertyStateListener> listeners = getListeners(source,
false);
+
+ if (listeners == null)
+ {
+ return;
+ }
+
+ boolean wasListening = (listeners.size() != 0);
+
+ listeners.remove(listener);
+
+ if (wasListening && listeners.size() == 0)
+ {
+ listeningStopped(source);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public final PropertyStateListener[] getPropertyStateListeners(S
source)
+ {
+ List<PropertyStateListener> listeners = getListeners(source,
false);
+
+ if (listeners == null)
+ {
+ return new PropertyStateListener[0];
+ }
+
+ PropertyStateListener[] ret = new
PropertyStateListener[listeners.size()];
+ ret = listeners.toArray(ret);
+ return ret;
+ }
+
+ /**
+ * Notify listeners that the state of this property has changed, as
+ * characterized by the given {@code PropertyStateEvent}. If this
+ * {@code AbstractXProperty} is managing listeners for multiple
sources, only
+ * the listeners associated with the object returned by the
+ * {@code PropertyStateEvent's getSourceObject()} method are notified.
+ *
+ * @param pse the {@code PropertyStateEvent} characterizing the state
change
+ */
+ protected final void firePropertyStateChange(PropertyStateEvent pse)
+ {
+ List<PropertyStateListener> listeners = getListeners((S)
pse.getSourceObject(), false);
+
+ if (listeners == null)
+ {
+ return;
+ }
+
+ for (PropertyStateListener listener : listeners)
+ {
+ listener.propertyStateChanged(pse);
+ }
+ }
+
+ /**
+ * Returns whether or not there are any {@code PropertyStateListeners}
+ * installed for the given source object.
+ *
+ * @param source the source object of interest
+ * @return whether or not there are any {@code PropertyStateListeners}
+ * installed for the given source object
+ */
+ public final boolean isListening(S source)
+ {
+ List<PropertyStateListener> listeners = getListeners(source,
false);
+ return listeners != null && listeners.size() != 0;
+ }
+
+}
=======================================
--- /dev/null
+++
/XProperty/src/main/java/org/betterbeansbinding/xproperty/propertyFactory/ImplementationClassGenerationStrategy.java
Thu Aug 27 11:14:44 2009
@@ -0,0 +1,144 @@
+package org.betterbeansbinding.xproperty.propertyFactory;
+
+import javassist.*;
+import org.betterbeansbinding.util.javassist.ClassPoolClassLoader;
+import org.betterbeansbinding.xproperty.Property$;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+/**
+ * @author Peter Levart
+ */
+public interface ImplementationClassGenerationStrategy
+{
+ ClassLoader getImplementationClassLoader(
+ Class<? extends Property$<?, ?>> property$Class
+ );
+
+ <P$ extends Property$<?, ?>> Class<? extends P$>
createImplementationClass(
+ Class<P$> property$Class,
+ String implementationClassName,
+ PropertyMethodNamingStrategy propertyMethodNamingStrategy,
+ ImplementationMembersGenerationStrategy
implementationMembersGenerationStrategy
+ );
+
+ enum Impl implements ImplementationClassGenerationStrategy
+ {
+ JAVASSIST
+ {
+ private final Map<ClassLoader,
Reference<ClassPoolClassLoader>> classPoolClassLoaders
+ = new WeakHashMap<ClassLoader,
Reference<ClassPoolClassLoader>>();
+
+ @Override
+ public ClassPoolClassLoader
getImplementationClassLoader(Class<? extends Property$<?, ?>>
property$Class)
+ {
+ ClassLoader classLoader =
property$Class.getClassLoader();
+ ClassPoolClassLoader implClassLoader;
+
+ synchronized (classPoolClassLoaders)
+ {
+ Reference<ClassPoolClassLoader> implClassLoaderRef
= classPoolClassLoaders.get(classLoader);
+ implClassLoader = implClassLoaderRef == null ?
null : implClassLoaderRef.get();
+ if (implClassLoader == null)
+ {
+ implClassLoader =
ClassPoolClassLoader.newInstanceWithBoundPool(classLoader);
+ classPoolClassLoaders.put(classLoader, new
WeakReference<ClassPoolClassLoader>(implClassLoader));
+ }
+ }
+
+ return implClassLoader;
+ }
+
+ @Override
+ public <P$ extends Property$<?, ?>> Class<? extends P$>
createImplementationClass(
+ Class<P$> property$Class,
+ String implementationClassName,
+ PropertyMethodNamingStrategy
propertyMethodNamingStrategy,
+ ImplementationMembersGenerationStrategy
implementationMembersGenerationStrategy
+ )
+ {
+ try
+ {
+ return createOrThrow(property$Class,
implementationClassName, propertyMethodNamingStrategy,
implementationMembersGenerationStrategy);
+ }
+ catch (NotFoundException e)
+ {
+ throw new RuntimeException(e);
+ }
+ catch (CannotCompileException e)
+ {
+ throw new RuntimeException(e);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private <P$ extends Property$<?, ?>> Class<? extends P$>
createOrThrow(
+ Class<P$> property$Class,
+ String implementationClassName,
+ PropertyMethodNamingStrategy
propertyMethodNamingStrategy,
+ ImplementationMembersGenerationStrategy
implementationMembersGenerationStrategy
+ ) throws NotFoundException, CannotCompileException,
ClassNotFoundException
+ {
+ ClassPoolClassLoader implClassLoader =
getImplementationClassLoader(property$Class);
+ ClassPool pool = implClassLoader.getClassPool();
+
+ Class<?> superclass =
implementationMembersGenerationStrategy.getImplementationClassSuperclass(property$Class);
+
+ String unqualifiedName =
getUnqualifiedName(implementationClassName);
+
+ CtClass ctClass = superclass == null
+ ?
pool.makeClass(implementationClassName)
+ :
pool.makeClass(implementationClassName,
pool.getCtClass(superclass.getName()));
+
+ Class<?>[] interfaces =
implementationMembersGenerationStrategy.getImplementationClassInterfaces(property$Class);
+ if (interfaces != null)
+ for (Class<?> interfaze : interfaces)
+
ctClass.addInterface(pool.getCtClass(interfaze.getName()));
+
+ ctClass.addConstructor(
+ CtNewConstructor.make(
+
implementationMembersGenerationStrategy.getImplementationClassConstructor(unqualifiedName),
+ ctClass
+ )
+ );
+
+ for (Method method : property$Class.getMethods())
+ {
+ if
(propertyMethodNamingStrategy.isAbstractPropertyMethod(method))
+ {
+ String propertyName =
propertyMethodNamingStrategy.getPropertyName(method);
+
+ ctClass.addMethod(
+ CtNewMethod.make(
+
implementationMembersGenerationStrategy.getImplementationClassPropertyMethod(method,
propertyName),
+ ctClass
+ )
+ );
+ }
+ else if
(Modifier.isAbstract(method.getModifiers()))
+ {
+ throw new IllegalArgumentException("Don't know
how to implement the following abstract method: " + method);
+ }
+ }
+
+ Class<?> implementationClass =
implClassLoader.loadClass(ctClass.getName());
+
+ return implementationClass.asSubclass(property$Class);
+ }
+ };
+
+ private static String getUnqualifiedName(String className)
+ {
+ int lastDot = className.lastIndexOf('.');
+ return lastDot < 0 ? className : className.substring(lastDot +
1);
+ }
+ }
+}
=======================================
--- /dev/null
+++
/XProperty/src/main/java/org/betterbeansbinding/xproperty/propertyFactory/ImplementationClassNamingStrategy.java
Thu Aug 27 11:14:44 2009
@@ -0,0 +1,40 @@
+package org.betterbeansbinding.xproperty.propertyFactory;
+
+import org.betterbeansbinding.xproperty.Property$;
+
+/**
+ * @author Peter Levart
+ */
+public interface ImplementationClassNamingStrategy
+{
+ String getImplementationClassName(Class<? extends Property$<?, ?>>
property$Class);
+
+ enum Impl implements ImplementationClassNamingStrategy
+ {
+ DEFAULT // some.package.Property$ClassName ->
some.package.propertyImpl.Property$ClassNameImpl
+ {
+ @Override
+ public String getImplementationClassName(Class<? extends
Property$<?, ?>> property$Class)
+ {
+ String className = property$Class.getName();
+ String packageName, unqualifiedName;
+
+ int lastDot = className.lastIndexOf('.');
+ if (lastDot < 0)
+ {
+ packageName = null;
+ unqualifiedName = className;
+ }
+ else
+ {
+ packageName = className.substring(0, lastDot);
+ unqualifiedName = className.substring(lastDot + 1);
+ }
+
+ return packageName == null
+ ? "propertyImpl." + unqualifiedName + "Impl"
+ : packageName + ".propertyImpl." +
unqualifiedName + "Impl";
+ }
+ }
+ }
+}
=======================================
--- /dev/null
+++
/XProperty/src/main/java/org/betterbeansbinding/xproperty/propertyFactory/ImplementationMembersGenerationStrategy.java
Thu Aug 27 11:14:44 2009
@@ -0,0 +1,57 @@
+package org.betterbeansbinding.xproperty.propertyFactory;
+
+import org.betterbeansbinding.util.ClassNameUtils;
+import org.betterbeansbinding.xproperty.Property$;
+
+import java.lang.reflect.Method;
+
+/**
+ * @author Peter Levart
+ */
+public interface ImplementationMembersGenerationStrategy
+{
+ Class<?> getImplementationClassSuperclass(Class<? extends
Property$<?, ?>> propetry$Class);
+
+ Class<?>[] getImplementationClassInterfaces(Class<? extends
Property$<?, ?>> propetry$Class);
+
+ String getImplementationClassConstructor(String
implementationClassUnqualifiedName);
+
+ String getImplementationClassPropertyMethod(Method
abstractPropertyMethod, String propertyName);
+
+ enum Impl implements ImplementationMembersGenerationStrategy
+ {
+ DEFAULT
+ {
+ @Override
+ public Class<?> getImplementationClassSuperclass(Class<?
extends Property$<?, ?>> propetry$Class)
+ {
+ return propetry$Class;
+ }
+ @Override
+ public Class<?>[] getImplementationClassInterfaces(Class<?
extends Property$<?, ?>> propetry$Class)
+ {
+ return null;
+ }
+ @Override
+ public String getImplementationClassConstructor(String
implementationClassUnqualifiedName)
+ {
+ return
+ " public " + implementationClassUnqualifiedName
+ "(org.jdesktop.beansbinding.Property property)\n" +
+ " {\n" +
+ " init(property);\n" +
+ " }\n";
+ }
+ @Override
+ public String getImplementationClassPropertyMethod(Method
abstractPropertyMethod, String propertyName)
+ {
+ String methodReturnTypeName =
ClassNameUtils.getJavaSourceName(abstractPropertyMethod.getReturnType());
+
+ return
+ " public " + methodReturnTypeName + " " +
abstractPropertyMethod.getName() + "()\n" +
+ " {\n" +
+ " return (" + methodReturnTypeName + ")
subProperty(" + methodReturnTypeName + ".class, \"" + propertyName
+ "\");\n" +
+ " }\n";
+ }
+ }
+ }
+}
=======================================
--- /dev/null
+++
/XProperty/src/main/java/org/betterbeansbinding/xproperty/propertyFactory/PropertyMethodNamingStrategy.java
Thu Aug 27 11:14:44 2009
@@ -0,0 +1,43 @@
+package org.betterbeansbinding.xproperty.propertyFactory;
+
+import org.betterbeansbinding.xproperty.Property$;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+/**
+ * @author Peter Levart
+ */
+public interface PropertyMethodNamingStrategy
+{
+ boolean isAbstractPropertyMethod(Method method);
+
+ String getPropertyName(Method propertyMethod);
+
+ enum Impl implements PropertyMethodNamingStrategy
+ {
+ DEFAULT
+ {
+ @Override
+ public boolean isAbstractPropertyMethod(Method method)
+ {
+ int mods = method.getModifiers();
+ return Modifier.isAbstract(mods) &&
+ Modifier.isPublic(mods) &&
+ method.getName().endsWith("$") &&
+ method.getParameterTypes().length == 0 &&
+ method.getExceptionTypes().length == 0 &&
+
Property$.class.isAssignableFrom(method.getReturnType());
+ }
+
+ @Override
+ public String getPropertyName(Method method)
+ {
+ if (!isAbstractPropertyMethod(method))
+ throw new IllegalArgumentException("Method: " +
method + " is not an abstract property method");
+
+ return method.getName().substring(0,
method.getName().length() - 1);
+ }
+ }
+ }
+}
=======================================
--- /dev/null
+++
/XProperty/src/test/java/org/betterbeansbinding/xproperty/AbstractBean.java
Thu Aug 27 11:14:44 2009
@@ -0,0 +1,113 @@
+package org.betterbeansbinding.xproperty;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+/**
+ * @author Peter Levart
+ */
+public class AbstractBean implements Cloneable
+{
+ // registering property change listeners
+
+ private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
+
+ //
+ // PropertyChangeSource
+
+ public void removePropertyChangeListener(String propertyName,
PropertyChangeListener listener)
+ {
+ pcs.removePropertyChangeListener(propertyName, listener);
+ }
+
+ public void removePropertyChangeListener(PropertyChangeListener
listener)
+ {
+ pcs.removePropertyChangeListener(listener);
+ }
+
+ public boolean hasListeners(String propertyName)
+ {
+ return pcs.hasListeners(propertyName);
+ }
+
+ public PropertyChangeListener[] getPropertyChangeListeners(String
propertyName)
+ {
+ return pcs.getPropertyChangeListeners(propertyName);
+ }
+
+ public PropertyChangeListener[] getPropertyChangeListeners()
+ {
+ return pcs.getPropertyChangeListeners();
+ }
+
+ public void addPropertyChangeListener(String propertyName,
PropertyChangeListener listener)
+ {
+ pcs.addPropertyChangeListener(propertyName, listener);
+ }
+
+ public void addPropertyChangeListener(PropertyChangeListener listener)
+ {
+ pcs.addPropertyChangeListener(listener);
+ }
+
+ //
+ // fireing property change events
+
+ protected void firePropertyChange(String propertyName, Object
oldValue, Object newValue)
+ {
+ pcs.firePropertyChange(propertyName, oldValue, newValue);
+ }
+
+ protected void firePropertyChange(String propertyName, int oldValue,
int newValue)
+ {
+ pcs.firePropertyChange(propertyName, oldValue, newValue);
+ }
+
+ protected void firePropertyChange(String propertyName, boolean
oldValue, boolean newValue)
+ {
+ pcs.firePropertyChange(propertyName, oldValue, newValue);
+ }
+
+ protected void firePropertyChange(PropertyChangeEvent evt)
+ {
+ pcs.firePropertyChange(evt);
+ }
+
+ protected void fireIndexedPropertyChange(String propertyName, int
index, Object oldValue, Object newValue)
+ {
+ pcs.fireIndexedPropertyChange(propertyName, index, oldValue,
newValue);
+ }
+
+ protected void fireIndexedPropertyChange(String propertyName, int
index, int oldValue, int newValue)
+ {
+ pcs.fireIndexedPropertyChange(propertyName, index, oldValue,
newValue);
+ }
+
+ protected void fireIndexedPropertyChange(String propertyName, int
index, boolean oldValue, boolean newValue)
+ {
+ pcs.fireIndexedPropertyChange(propertyName, index, oldValue,
newValue);
+ }
+
+ /**
+ * @return a clone of this bean (shallow copy) but with empty list of
PropertyChangeListeners
+ */
+ @SuppressWarnings({"CloneDoesntDeclareCloneNotSupportedException"})
+ @Override
+ public AbstractBean clone()
+ {
+ try
+ {
+ AbstractBean clone = (AbstractBean) super.clone();
+
+ // clear any listeners
+ clone.pcs = new PropertyChangeSupport(clone);
+
+ return clone;
+ }
+ catch (CloneNotSupportedException e)
+ {
+ throw new AssertionError("Should not happen");
+ }
+ }
+}
=======================================
--- /dev/null
+++ /XProperty/src/test/java/org/betterbeansbinding/xproperty/Address.java
Thu Aug 27 11:14:44 2009
@@ -0,0 +1,70 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.betterbeansbinding.xproperty;
+
+/**
+ * @author peterl
+ */
+public class Address extends AbstractBean
+{
+ @SuppressWarnings({"unchecked"})
+ public static final $<Address, Address> $ =
Property$Factory.create($.class);
+
+ public static abstract class $<S, V extends Address> extends
Property$<S, V>
+ {
+ public abstract Property$<S, String> street$();
+
+ public abstract Property$<S, Integer> houseNumber$();
+
+ public abstract Property$<S, String> city$();
+
+ public abstract Property$<S, String> country$();
+ }
+
+ private String street;
+ private int houseNumber;
+ private String city;
+ private String country;
+
+ public String getCity()
+ {
+ return city;
+ }
+
+ public void setCity(String city)
+ {
+ firePropertyChange("city", this.city, this.city = city);
+ }
+
+ public String getCountry()
+ {
+ return country;
+ }
+
+ public void setCountry(String country)
+ {
+ firePropertyChange("country", this.country, this.country =
country);
+ }
+
+ public int getHouseNumber()
+ {
+ return houseNumber;
+ }
+
+ public void setHouseNumber(int houseNumber)
+ {
+ firePropertyChange("houseNumber", this.houseNumber,
this.houseNumber = houseNumber);
+ }
+
+ public String getStreet()
+ {
+ return street;
+ }
+
+ public void setStreet(String street)
+ {
+ firePropertyChange("street", this.street, this.street = street);
+ }
+}
=======================================
--- /dev/null
+++ /XProperty/src/test/java/org/betterbeansbinding/xproperty/Employee.java
Thu Aug 27 11:14:44 2009
@@ -0,0 +1,44 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.betterbeansbinding.xproperty;
+
+/**
+ * @author peterl
+ */
+public class Employee extends Person
+{
+ @SuppressWarnings({"unchecked"})
+ public static final $<Employee, Employee> $ =
Property$Factory.create($.class);
+
+ public static abstract class $<S, V extends Employee> extends
Person.$<S, V>
+ {
+ public abstract Property$<S, String> descriptiveAddress$();
+
+ public abstract Property$<S, String> employeeNumber$();
+ }
+
+ private String descriptiveAddress;
+ private String employeeNumber;
+
+ public String getDescriptiveAddress()
+ {
+ return descriptiveAddress;
+ }
+
+ public void setDescriptiveAddress(String descriptiveAddress)
+ {
+ firePropertyChange("descriptiveAddress", this.descriptiveAddress,
this.descriptiveAddress = descriptiveAddress);
+ }
+
+ public String getEmployeeNumber()
+ {
+ return employeeNumber;
+ }
+
+ public void setEmployeeNumber(String employeeNumber)
+ {
+ firePropertyChange("employeeNumber", this.employeeNumber,
this.employeeNumber = employeeNumber);
+ }
+}
=======================================
--- /dev/null
+++ /XProperty/src/test/java/org/betterbeansbinding/xproperty/Person.java
Thu Aug 27 11:14:44 2009
@@ -0,0 +1,57 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.betterbeansbinding.xproperty;
+
+/**
+ * @author peterl
+ */
+public class Person extends AbstractBean
+{
+ @SuppressWarnings({"unchecked"})
+ public static final $<Person, Person> $ =
Property$Factory.create($.class);
+
+ public static abstract class $<S, V extends Person> extends
Property$<S, V>
+ {
+ public abstract Property$<S, String> name$();
+
+ public abstract Property$<S, Integer> age$();
+
+ public abstract Address.$<S, Address> address$();
+ }
+
+ private String name;
+ private int age;
+ private Address address;
+
+ public Address getAddress()
+ {
+ return address;
+ }
+
+ public void setAddress(Address address)
+ {
+ firePropertyChange("address", this.address, this.address =
address);
+ }
+
+ public int getAge()
+ {
+ return age;
+ }
+
+ public void setAge(int age)
+ {
+ firePropertyChange("age", this.age, this.age = age);
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ firePropertyChange("name", this.name, this.name = name);
+ }
+}
=======================================
--- /dev/null
+++
/XProperty/src/test/java/org/betterbeansbinding/xproperty/PropsTest.java
Thu Aug 27 11:14:44 2009
@@ -0,0 +1,53 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.betterbeansbinding.xproperty;
+
+import static org.betterbeansbinding.xproperty.ExpressionProperty.format;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author peterl
+ */
+public class PropsTest
+{
+ @Test
+ public void testProps()
+ {
+ Employee employee = new Employee();
+ Address address = new Address();
+ address.setStreet("Rožna pot");
+ address.setHouseNumber(12);
+ address.setCity("Dragomer");
+ address.setCountry("Slovenija");
+
+ format(
+ "%1$s %2$d, %3$s, %4$s",
+ Employee.$.address$().street$(),
+ Employee.$.address$().houseNumber$(),
+ Employee.$.address$().city$(),
+ Employee.$.address$().country$()
+ ).of(employee).readBind(
+ Employee.$.descriptiveAddress$()
+ .of(employee)
+ );
+
+ employee.setAddress(address);
+ Assert.assertEquals(employee.getDescriptiveAddress(), "Rožna pot
12, Dragomer, Slovenija");
+
+ address.setCity("Brezovica pri Ljubljani");
+ Assert.assertEquals(employee.getDescriptiveAddress(), "Rožna pot
12, Brezovica pri Ljubljani, Slovenija");
+
+ // another...
+
+ Person.$.name$().of(employee).readBind(
+ Employee.$.employeeNumber$().of(employee)
+ );
+
+ employee.setName("XYZ");
+ Assert.assertEquals(employee.getEmployeeNumber(), "XYZ");
+ }
+
+}

==============================================================================
Revision: ed282b08cf
Author: 5er_levart
Date: Sat Aug 29 09:31:41 2009
Log: got rid of all strings as property names
http://code.google.com/p/betterbeansbinding/source/detail?repo=incubator&r=ed282b08cf

Modified:
/XProperty/src/test/java/org/betterbeansbinding/xproperty/Address.java
/XProperty/src/test/java/org/betterbeansbinding/xproperty/Employee.java
/XProperty/src/test/java/org/betterbeansbinding/xproperty/Person.java

=======================================
--- /XProperty/src/test/java/org/betterbeansbinding/xproperty/Address.java
Thu Aug 27 11:14:44 2009
+++ /XProperty/src/test/java/org/betterbeansbinding/xproperty/Address.java
Sat Aug 29 09:31:41 2009
@@ -35,7 +35,7 @@

public void setCity(String city)
{
- firePropertyChange("city", this.city, this.city = city);
+ firePropertyChange($.city$().getPropertyPath(), this.city,
this.city = city);
}

public String getCountry()
@@ -45,7 +45,7 @@

public void setCountry(String country)
{
- firePropertyChange("country", this.country, this.country =
country);
+ firePropertyChange($.country$().getPropertyPath(), this.country,
this.country = country);
}

public int getHouseNumber()
@@ -55,7 +55,7 @@

public void setHouseNumber(int houseNumber)
{
- firePropertyChange("houseNumber", this.houseNumber,
this.houseNumber = houseNumber);
+ firePropertyChange($.houseNumber$().getPropertyPath(),
this.houseNumber, this.houseNumber = houseNumber);
}

public String getStreet()
@@ -65,6 +65,6 @@

public void setStreet(String street)
{
- firePropertyChange("street", this.street, this.street = street);
+ firePropertyChange($.street$().getPropertyPath(), this.street,
this.street = street);
}
}
=======================================
--- /XProperty/src/test/java/org/betterbeansbinding/xproperty/Employee.java
Thu Aug 27 11:14:44 2009
+++ /XProperty/src/test/java/org/betterbeansbinding/xproperty/Employee.java
Sat Aug 29 09:31:41 2009
@@ -29,7 +29,7 @@

public void setDescriptiveAddress(String descriptiveAddress)
{
- firePropertyChange("descriptiveAddress", this.descriptiveAddress,
this.descriptiveAddress = descriptiveAddress);
+ firePropertyChange($.descriptiveAddress$().getPropertyPath(),
this.descriptiveAddress, this.descriptiveAddress = descriptiveAddress);
}

public String getEmployeeNumber()
@@ -39,6 +39,6 @@

public void setEmployeeNumber(String employeeNumber)
{
- firePropertyChange("employeeNumber", this.employeeNumber,
this.employeeNumber = employeeNumber);
+ firePropertyChange($.employeeNumber$().getPropertyPath(),
this.employeeNumber, this.employeeNumber = employeeNumber);
}
}
=======================================
--- /XProperty/src/test/java/org/betterbeansbinding/xproperty/Person.java
Thu Aug 27 11:14:44 2009
+++ /XProperty/src/test/java/org/betterbeansbinding/xproperty/Person.java
Sat Aug 29 09:31:41 2009
@@ -32,7 +32,7 @@

public void setAddress(Address address)
{
- firePropertyChange("address", this.address, this.address =
address);
+ firePropertyChange($.address$().getPropertyPath(), this.address,
this.address = address);
}

public int getAge()
@@ -42,7 +42,7 @@

public void setAge(int age)
{
- firePropertyChange("age", this.age, this.age = age);
+ firePropertyChange($.age$().getPropertyPath(), this.age, this.age
= age);
}

public String getName()
@@ -52,6 +52,6 @@

public void setName(String name)
{
- firePropertyChange("name", this.name, this.name = name);
+ firePropertyChange($.name$().getPropertyPath(), this.name,
this.name = name);
}
}
Reply all
Reply to author
Forward
0 new messages