Skip to content

Commit

Permalink
#163: improved test for equals and hashCode, added BeanFactory.copy m…
Browse files Browse the repository at this point in the history
…ethod, improved getRequiredProperty exception message, fixed property access.
  • Loading branch information
hohwille committed Jan 6, 2016
1 parent b8998bb commit 27321a7
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ public interface BeanAccess {
*/
GenericProperty<?> getProperty(String name);

/**
* @return the {@link Class} reflecting the owning {@link Bean}.
*/
Class<? extends Bean> getBeanClass();

/**
* @param name the {@link GenericProperty#getName() name} of the requested property.
* @return the requested {@link GenericProperty}.
Expand All @@ -39,7 +44,7 @@ default GenericProperty<?> getRequiredProperty(String name) throws PojoPropertyN

GenericProperty<?> property = getProperty(name);
if (property == null) {
throw new PojoPropertyNotFoundException(getClass(), name);
throw new PojoPropertyNotFoundException(getBeanClass(), name);
}
return property;
}
Expand Down Expand Up @@ -158,8 +163,8 @@ default <V> void setPropertyValue(String name, V value, GenericType<V> type) {
boolean isDynamic();

/**
* @return <code>true</code> if this {@link BeanAccess} belongs to a {@link BeanFactory#createPrototype(Class) prototype}
* , <code>false</code> otherwise (if it belongs to an {@link BeanFactory#create(Bean) instance}).
* @return <code>true</code> if this {@link BeanAccess} belongs to a {@link BeanFactory#createPrototype(Class)
* prototype} , <code>false</code> otherwise (if it belongs to an {@link BeanFactory#create(Bean) instance}).
*/
boolean isPrototype();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,14 @@ default <BEAN extends Bean> BEAN create(Class<BEAN> type) {
*/
<BEAN extends Bean> BEAN getReadOnlyBean(BEAN bean);

/**
* Creates a copy of the given {@link Bean}.
*
* @param <BEAN> the generic type of the {@link Bean}.
* @param bean the bean to make {@link BeanAccess#isReadOnly() read-only}.
* @return the {@link BeanAccess#isReadOnly() read-only} view on the given bean. Will be the given instance if already
* {@link BeanAccess#isReadOnly() read-only}.
*/
<BEAN extends Bean> BEAN copy(BEAN bean);

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,26 @@
public abstract class BeanAccessBase<BEAN extends Bean>
implements InvocationHandler, BeanAccess, Iterable<GenericProperty<?>> {

private final Class<BEAN> beanType;
private final Class<BEAN> beanClass;

private final BEAN bean;

/**
* The constructor.
*
* @param beanType - see {@link #getBeanType()}.
* @param beanClass - see {@link #getBeanClass()}.
* @param beanFactory the owning {@link BeanFactoryImpl}.
*/
public BeanAccessBase(Class<BEAN> beanType, BeanFactoryImpl beanFactory) {
public BeanAccessBase(Class<BEAN> beanClass, BeanFactoryImpl beanFactory) {
super();
this.beanType = beanType;
this.bean = beanFactory.createProxy(this, beanType);
this.beanClass = beanClass;
this.bean = beanFactory.createProxy(this, beanClass);
}

/**
* @return the {@link Class} reflecting the {@link #getBean() bean}.
*/
public Class<BEAN> getBeanType() {
@Override
public Class<BEAN> getBeanClass() {

return this.beanType;
return this.beanClass;
}

/**
Expand All @@ -68,7 +66,7 @@ public GenericProperty<?> getProperty(String name) {

BeanPrototypeProperty prototypeProperty = getPrototype().getName2PropertyMap().get(name);
if (prototypeProperty != null) {
return getProperty(prototypeProperty, false);
return getProperty(prototypeProperty, true);
}
return null;
}
Expand All @@ -77,11 +75,11 @@ public GenericProperty<?> getProperty(String name) {
* Gets the {@link GenericProperty} for the given <code>index</code>.
*
* @param prototypeProperty is the {@link BeanPrototypeProperty}.
* @param required - <code>true</code> if the property is required and shall be created if it {@link #isDynamic() does
* @param create - <code>true</code> if the property is required and shall be created if it {@link #isDynamic() does
* not already exist}, <code>false</code> otherwise.
* @return the requested {@link GenericProperty}. May be <code>null</code>.
*/
protected abstract GenericProperty<?> getProperty(BeanPrototypeProperty prototypeProperty, boolean required);
protected abstract GenericProperty<?> getProperty(BeanPrototypeProperty prototypeProperty, boolean create);

@Override
public boolean isReadOnly() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ public abstract class BeanAccessInstance<BEAN extends Bean> extends BeanAccessBa
/**
* The constructor.
*
* @param beanType - see {@link #getBeanType()}.
* @param beanClass - see {@link #getBeanClass()}.
* @param beanFactory the owning {@link BeanFactoryImpl}.
* @param prototype the {@link BeanAccessPrototype}.
*/
public BeanAccessInstance(Class<BEAN> beanType, BeanFactoryImpl beanFactory,
public BeanAccessInstance(Class<BEAN> beanClass, BeanFactoryImpl beanFactory,
BeanAccessPrototype<BEAN> prototype) {

super(beanType, beanFactory);
super(beanClass, beanFactory);
this.prototype = prototype;
this.properties = GenericProperty.NO_PROPERTIES;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ public class BeanAccessMutable<BEAN extends Bean> extends BeanAccessInstance<BEA
/**
* The constructor.
*
* @param beanType - see {@link #getBeanType()}.
* @param beanClass - see {@link #getBeanClass()}.
* @param beanFactory the owning {@link BeanFactoryImpl}.
* @param prototype the {@link BeanAccessPrototype}.
*/
public BeanAccessMutable(Class<BEAN> beanType, BeanFactoryImpl beanFactory,
public BeanAccessMutable(Class<BEAN> beanClass, BeanFactoryImpl beanFactory,
BeanAccessPrototype<BEAN> prototype) {

super(beanType, beanFactory, prototype);
super(beanClass, beanFactory, prototype);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ public class BeanAccessPrototype<BEAN extends Bean> extends BeanAccessBase<BEAN>
/**
* The constructor.
*
* @param beanType - see {@link #getBeanType()}.
* @param beanClass - see {@link #getBeanClass()}.
* @param beanFactory the owning {@link BeanFactoryImpl}.
*/
public BeanAccessPrototype(Class<BEAN> beanType, BeanFactoryImpl beanFactory) {
super(beanType, beanFactory);
this.beanType = beanType;
public BeanAccessPrototype(Class<BEAN> beanClass, BeanFactoryImpl beanFactory) {
super(beanClass, beanFactory);
this.beanType = beanClass;
this.name2PropertyMap = new HashMap<>();
this.method2OperationMap = new HashMap<>();
this.dynamic = false;
Expand Down Expand Up @@ -137,7 +137,7 @@ protected void addProperty(GenericPropertyImpl<?> property) {
* @return the type
*/
@Override
public Class<BEAN> getBeanType() {
public Class<BEAN> getBeanClass() {

return this.beanType;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class BeanAccessReadOnly<BEAN extends Bean> extends BeanAccessInstance<BE
*/
public BeanAccessReadOnly(BeanFactoryImpl beanFactory, BeanAccessPrototype<BEAN> prototype,
BeanAccessBase<BEAN> delegate) {
super(prototype.getBeanType(), beanFactory, prototype);
super(prototype.getBeanClass(), beanFactory, prototype);
this.delegate = delegate;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import javafx.beans.property.Property;
import net.sf.mmm.util.bean.api.Bean;
import net.sf.mmm.util.bean.api.BeanAccess;
import net.sf.mmm.util.bean.api.BeanFactory;
import net.sf.mmm.util.component.base.AbstractLoggableComponent;
import net.sf.mmm.util.property.api.GenericProperty;
Expand Down Expand Up @@ -115,6 +116,51 @@ <BEAN extends Bean> BEAN createProxy(BeanAccessBase<BEAN> access, Class<BEAN> be
return bean;
}

@SuppressWarnings("unchecked")
@Override
public <BEAN extends Bean> BEAN create(BEAN bean) {

BeanAccessBase<BEAN> access = (BeanAccessBase<BEAN>) bean.access();
BeanAccessPrototype<BEAN> beanPrototype = access.getPrototype();
BeanAccessMutable<BEAN> interceptor = new BeanAccessMutable<>(access.getBeanClass(), this, beanPrototype);
return interceptor.getBean();
}

@SuppressWarnings("unchecked")
@Override
public <BEAN extends Bean> BEAN getReadOnlyBean(BEAN bean) {

BeanAccessBase<BEAN> access = (BeanAccessBase<BEAN>) bean.access();
if (access.isReadOnly()) {
return bean;
}
BeanAccessPrototype<BEAN> beanPrototype = access.getPrototype();
BeanAccessReadOnly<BEAN> interceptor = new BeanAccessReadOnly<>(this, beanPrototype, access);
return interceptor.getBean();
}

@SuppressWarnings("unchecked")
@Override
public <BEAN extends Bean> BEAN getPrototype(BEAN bean) {

BeanAccessBase<BEAN> access = (BeanAccessBase<BEAN>) bean.access();
BeanAccessPrototype<BEAN> beanPrototype = access.getPrototype();
return beanPrototype.getBean();
}

@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public <BEAN extends Bean> BEAN copy(BEAN bean) {

BEAN copy = create(bean);
BeanAccess access = copy.access();
for (GenericProperty<?> property : bean.access().getProperties()) {
GenericProperty copyProperty = access.getRequiredProperty(property.getName());
copyProperty.setValue(property.getValue());
}
return copy;
}

@Override
public <BEAN extends Bean> BEAN createPrototype(Class<BEAN> type, boolean dynamic) {

Expand Down Expand Up @@ -345,36 +391,4 @@ private GenericPropertyImpl<?> createPropertyFromSpecifiedClass(String name, Gen
}
}

@SuppressWarnings("unchecked")
@Override
public <BEAN extends Bean> BEAN create(BEAN prototype) {

BeanAccessBase<BEAN> access = (BeanAccessBase<BEAN>) prototype.access();
BeanAccessPrototype<BEAN> beanPrototype = access.getPrototype();
BeanAccessMutable<BEAN> interceptor = new BeanAccessMutable<>(access.getBeanType(), this, beanPrototype);
return interceptor.getBean();
}

@SuppressWarnings("unchecked")
@Override
public <BEAN extends Bean> BEAN getReadOnlyBean(BEAN beanProxy) {

BeanAccessBase<BEAN> access = (BeanAccessBase<BEAN>) beanProxy.access();
if (access.isReadOnly()) {
return beanProxy;
}
BeanAccessPrototype<BEAN> beanPrototype = access.getPrototype();
BeanAccessReadOnly<BEAN> interceptor = new BeanAccessReadOnly<>(this, beanPrototype, access);
return interceptor.getBean();
}

@SuppressWarnings("unchecked")
@Override
public <BEAN extends Bean> BEAN getPrototype(BEAN bean) {

BeanAccessBase<BEAN> access = (BeanAccessBase<BEAN>) bean.access();
BeanAccessPrototype<BEAN> beanPrototype = access.getPrototype();
return beanPrototype.getBean();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import com.fasterxml.jackson.databind.ObjectMapper;

import net.sf.mmm.test.ObjectHelper;
import net.sf.mmm.util.bean.api.Bean;
import net.sf.mmm.util.bean.api.BeanAccess;
import net.sf.mmm.util.bean.api.BeanFactory;
Expand Down Expand Up @@ -47,16 +48,16 @@ public void testExamplePropertyBean() {

BeanFactory beanFactory = getBeanFactory();
ExamplePropertyBean bean = beanFactory.create(ExamplePropertyBean.class);
verifyBean(bean);
verifyExamplePropertyBean(bean);
verifyBean(bean, beanFactory);
verifyExamplePropertyBean(bean, beanFactory);
}

@Test
public void testExamplePojoBean() {

BeanFactory beanFactory = getBeanFactory();
ExamplePojoBean bean = beanFactory.create(ExamplePojoBean.class);
verifyBean(bean);
verifyBean(bean, beanFactory);
verifyExamplePojoBean(bean);
}

Expand All @@ -65,19 +66,19 @@ public void testExampleBean() {

BeanFactory beanFactory = getBeanFactory();
ExampleBean bean = beanFactory.create(ExampleBean.class);
verifyBean(bean);
verifyBean(bean, beanFactory);
verifyExamplePojoBean(bean);
verifyExamplePropertyBean(bean);
verifyExamplePropertyBean(bean, beanFactory);

assertThat(bean.self()).isSameAs(bean);
assertThat(bean.sayHi("Peter")).isEqualTo("Hi Peter");
}

private void verifyBean(Bean bean) {
private void verifyBean(Bean bean, BeanFactory beanFactory) {

BeanAccess access = bean.access();
assertThat(access).isNotNull();
assertThat(((BeanAccessBase) access).getBean()).isSameAs(bean);
assertThat(((BeanAccessBase<?>) access).getBean()).isSameAs(bean);
String undefinedProperty = "UndefinedProperty";
assertThat(access.getProperty(undefinedProperty)).isNull();
PojoPropertyNotFoundException error = null;
Expand All @@ -93,9 +94,12 @@ private void verifyBean(Bean bean) {
.isSameAs(access.getRequiredProperty(name))
.isSameAs(access.getOrCreateProperty(name, property.getType()));
}

// test equals
ObjectHelper.checkEqualsAndHashCode(bean, beanFactory.copy(bean), true);
}

private void verifyExamplePropertyBean(ExamplePropertyBean bean) {
private void verifyExamplePropertyBean(ExamplePropertyBean bean, BeanFactory beanFactory) {

assertThat(bean).isNotNull();
assertThat(bean.Name()).isInstanceOf(StringPropertyImpl.class);
Expand Down Expand Up @@ -169,6 +173,11 @@ private void verifyExamplePropertyBean(ExamplePropertyBean bean) {
} catch (Exception e) {
fail("Failed to parse bean.toString() as JSON: " + json, e);
}

// equals and hashCode
ExamplePropertyBean copy = beanFactory.copy(bean);
copy.Name().setValue("Heinz");
ObjectHelper.checkEqualsAndHashCode(bean, copy, false);
}

private void verifyExamplePojoBean(ExamplePojoBean bean) {
Expand Down
1 change: 0 additions & 1 deletion mmm-util-test/src/main/java/net/sf/mmm/test/TestUser.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
* This is a simple user for testing. It acts as {@link java.security.Principal} and {@link Authentication}.
*
* @author Joerg Hohwiller (hohwille at users.sourceforge.net)
* @since 0
*/
public class TestUser implements Authentication {

Expand Down

0 comments on commit 27321a7

Please sign in to comment.