Skip to content

Commit

Permalink
#163: support for custom name as arg when creating prototype, naming …
Browse files Browse the repository at this point in the history
…convention for PropertyFactory impls changed, fixed PropertyFactoryManagerImpl
  • Loading branch information
hohwille committed Feb 7, 2016
1 parent 792785f commit 067c928
Show file tree
Hide file tree
Showing 18 changed files with 343 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,42 +81,62 @@ default ValidationFailure validate() {
*
* @param <V> the generic type of the {@link WritableProperty#getValue() property value}.
* @param name the {@link WritableProperty#getName() property name}.
* @param type the {@link WritableProperty#getType() property type}.
* @param valueType the {@link WritableProperty#getType() property type}.
* @return the requested property.
*/
@SuppressWarnings("unchecked")
default <V> WritableProperty<V> getOrCreateProperty(String name, GenericType<V> type) {
default <V> WritableProperty<V> getOrCreateProperty(String name, GenericType<V> valueType) {

WritableProperty<?> property = getProperty(name);
if (property != null) {
if (!property.getType().equals(type)) {
throw new ObjectMismatchException(type, property.getType(), getBeanClass(), name + ".type");
if (!property.getType().equals(valueType)) {
throw new ObjectMismatchException(valueType, property.getType(), getBeanClass(), name + ".type");
}
return (WritableProperty<V>) property;
}
return createProperty(name, type);
return createProperty(name, valueType);
}

/**
* {@link #getProperty(String) Gets} or {@link #createProperty(String, Class) creates} the specified property. If the
* property already exists it also has to match the given {@code type} or an exception will be thrown.
*
* @param <V> the generic type of the {@link WritableProperty#getValue() property value}.
* @param <PROPERTY> the generic type of the {@link WritableProperty property}.
* @param name the {@link WritableProperty#getName() property name}.
* @param type the Class reflecting the {@link WritableProperty} to create.
* @param propertyType the Class reflecting the {@link WritableProperty} to create.
* @return the requested property.
*/
default <PROPERTY extends WritableProperty<?>> PROPERTY getOrCreateProperty(String name, Class<PROPERTY> type) {
default <V, PROPERTY extends WritableProperty<V>> PROPERTY getOrCreateProperty(String name,
Class<PROPERTY> propertyType) {

GenericType<V> valueType = null;
return getOrCreateProperty(name, valueType, propertyType);
}

/**
* {@link #getProperty(String) Gets} or {@link #createProperty(String, Class) creates} the specified property. If the
* property already exists it also has to match the given {@code type} or an exception will be thrown.
*
* @param <V> the generic type of the {@link WritableProperty#getValue() property value}.
* @param <PROPERTY> the generic type of the {@link WritableProperty property}.
* @param name the {@link WritableProperty#getName() property name}.
* @param valueType the {@link WritableProperty#getType() property type}.
* @param propertyType the Class reflecting the {@link WritableProperty} to create.
* @return the requested property.
*/
default <V, PROPERTY extends WritableProperty<V>> PROPERTY getOrCreateProperty(String name,
GenericType<V> valueType, Class<PROPERTY> propertyType) {

WritableProperty<?> property = getProperty(name);
if (property != null) {
try {
return type.cast(property);
return propertyType.cast(property);
} catch (ClassCastException e) {
throw new ObjectMismatchException(e, type, property.getClass(), getBeanClass(), name + ".class");
throw new ObjectMismatchException(e, propertyType, property.getClass(), getBeanClass(), name + ".class");
}
}
return createProperty(name, type);
return createProperty(name, valueType, propertyType);
}

/**
Expand All @@ -137,19 +157,26 @@ default Object getPropertyValue(String name) {
* @param name the {@link WritableProperty#getName() name} of the property.
* @param value new {@link WritableProperty#getValue() value} of the specified property.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
default void setPropertyValue(String name, Object value) {

setPropertyValue(name, value, null);
WritableProperty<?> property = getRequiredProperty(name);
((WritableProperty) property).setValue(value);
}

/**
* This method sets the {@link WritableProperty property} with the given {@link WritableProperty#getName() name} to
* the specified {@code value}.
* the specified {@code value}. If the {@link WritableProperty property} does not already exist, it will
* {@link #isDynamic() dynamically} be {@link #createProperty(String, GenericType) created}.
*
* @param <V> the generic type of the {@link WritableProperty#getValue() property value}.
* @param name the {@link WritableProperty#getName() property name}.
* @param value new {@link WritableProperty#getValue() value} of the specified property.
* @param type the {@link WritableProperty#getType() property type}.
* @param value new {@link WritableProperty#getValue() value} of the specified property. Maybe {@code null} and in
* such case a missing {@link WritableProperty property} will NOT be
* {@link #createProperty(String, GenericType) created}.
* @param type the {@link WritableProperty#getType() property type}. May be <code>null</code> if the
* {@link WritableProperty property} has to be {@link #createProperty(String, GenericType) created} then the
* type will be derived from {@code value} as fallback.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
default <V> void setPropertyValue(String name, V value, GenericType<V> type) {
Expand All @@ -174,21 +201,44 @@ default <V> void setPropertyValue(String name, V value, GenericType<V> type) {
*
* @param <V> the generic type of the {@link WritableProperty#getValue() property value}.
* @param name the {@link WritableProperty#getName() property name}.
* @param type the {@link WritableProperty#getType() property type}.
* @param valueType the {@link WritableProperty#getType() property type}.
* @return the newly created property.
*/
<V> WritableProperty<V> createProperty(String name, GenericType<V> type);
default <V> WritableProperty<V> createProperty(String name, GenericType<V> valueType) {

return createProperty(name, valueType, null);
}

/**
* Creates and adds the specified {@link WritableProperty} on the fly. Creating and adding new properties is only
* possible for {@link #isDynamic() dynamic} beans.
*
* @param <V> the generic type of the {@link WritableProperty#getValue() property value}.
* @param <PROPERTY> the generic type of the {@link WritableProperty property}.
* @param name the {@link WritableProperty#getName() property name}.
* @param propertyType the Class reflecting the {@link WritableProperty} to create.
* @return the newly created property.
*/
default <V, PROPERTY extends WritableProperty<V>> PROPERTY createProperty(String name,
Class<PROPERTY> propertyType) {

GenericType<V> valueType = null;
return createProperty(name, valueType, propertyType);
}

/**
* Creates and adds the specified {@link WritableProperty} on the fly. Creating and adding new properties is only
* possible for {@link #isDynamic() dynamic} beans.
*
* @param <V> the generic type of the {@link WritableProperty#getValue() property value}.
* @param <PROPERTY> the generic type of the {@link WritableProperty property}.
* @param name the {@link WritableProperty#getName() property name}.
* @param type the Class reflecting the {@link WritableProperty} to create.
* @param valueType
* @param propertyType the Class reflecting the {@link WritableProperty} to create.
* @return the newly created property.
*/
<PROPERTY extends WritableProperty<?>> PROPERTY createProperty(String name, Class<PROPERTY> type);
<V, PROPERTY extends WritableProperty<V>> PROPERTY createProperty(String name, GenericType<V> valueType,
Class<PROPERTY> propertyType);

/**
* @see BeanFactory#getReadOnlyBean(Bean)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,32 @@ default <BEAN extends Bean> BEAN createPrototype(Class<BEAN> type) {
/**
* Creates a prototype of the given {@link Bean}. A prototype is used as template to {@link #create(Bean) create}
* regular {@link Bean}s. Such beans will inherit the defaults from the prototype what are the
* {@link BeanAccess#getProperties() available properties} as well as their default
* {@link WritableProperty#getValue() value}.
* {@link BeanAccess#getProperties() available properties} as well as their default {@link WritableProperty#getValue()
* value}.
*
* @param <BEAN> the generic type of the {@link Bean}.
* @param type the {@link Class} reflecting the {@link Bean}.
* @param dynamic the {@link BeanAccess#isDynamic() dynamic flag} of the {@link Bean}.
* @return the prototype instance of the specified {@link Bean}.
*/
<BEAN extends Bean> BEAN createPrototype(Class<BEAN> type, boolean dynamic);
default <BEAN extends Bean> BEAN createPrototype(Class<BEAN> type, boolean dynamic) {

return createPrototype(type, dynamic, null);
}

/**
* Creates a prototype of the given {@link Bean}. A prototype is used as template to {@link #create(Bean) create}
* regular {@link Bean}s. Such beans will inherit the defaults from the prototype what are the
* {@link BeanAccess#getProperties() available properties} as well as their default {@link WritableProperty#getValue()
* value}.
*
* @param <BEAN> the generic type of the {@link Bean}.
* @param type the {@link Class} reflecting the {@link Bean}.
* @param dynamic the {@link BeanAccess#isDynamic() dynamic flag} of the {@link Bean}.
* @param name the explicit {@link BeanAccess#getName() name} of the {@link Bean}.
* @return the prototype instance of the specified {@link Bean}.
*/
<BEAN extends Bean> BEAN createPrototype(Class<BEAN> type, boolean dynamic, String name);

/**
* @param <BEAN> the generic type of the {@link Bean}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,16 @@ public <V> WritableProperty<V> createProperty(String name, GenericType<V> type)
return (WritableProperty<V>) getProperty(name);
}

@SuppressWarnings("unchecked")
@Override
public <PROPERTY extends WritableProperty<?>> PROPERTY createProperty(String name, Class<PROPERTY> type) {
public <V, PROPERTY extends WritableProperty<V>> PROPERTY createProperty(String name, GenericType<V> valueType,
Class<PROPERTY> propertyType) {

if (isReadOnly()) {
throw new UnsupportedOperationException();
}
getPrototype().createProperty(name, type);
return type.cast(getProperty(name));
getPrototype().createProperty(name, valueType, propertyType);
return (PROPERTY) getProperty(name);
}

void createProperties() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,12 @@ public BeanAccessPrototype(Class<BEAN> beanClass, String name, BeanFactoryImpl b
* The constructor.
*
* @param master the {@link BeanAccessPrototype} to copy.
* @param name - see {@link #getName()}.
* @param dynamic - see {@link #isDynamic()}.
*/
public BeanAccessPrototype(BeanAccessPrototype<BEAN> master, boolean dynamic) {
public BeanAccessPrototype(BeanAccessPrototype<BEAN> master, boolean dynamic, String name) {

super(master.beanType, master.getName(), master.beanFactory);
super(master.beanType, name, master.beanFactory);
this.beanType = master.beanType;
this.name2PropertyMap = new HashMap<>(master.name2PropertyMap.size());
for (BeanPrototypeProperty prototypeProperty : master.name2PropertyMap.values()) {
Expand Down Expand Up @@ -103,8 +104,10 @@ public <V> WritableProperty<V> createProperty(String name, GenericType<V> proper
return property;
}

@SuppressWarnings("unchecked")
@Override
public <PROPERTY extends WritableProperty<?>> PROPERTY createProperty(String name, Class<PROPERTY> type) {
public <V, PROPERTY extends WritableProperty<V>> PROPERTY createProperty(String name, GenericType<V> valueType,
Class<PROPERTY> propertyType) {

if (!this.dynamic) {
throw new ReadOnlyException(this.beanType.getSimpleName(), "access.properties");
Expand All @@ -113,9 +116,9 @@ public <PROPERTY extends WritableProperty<?>> PROPERTY createProperty(String nam
if (prototypeProperty != null) {
throw new DuplicateObjectException(this, name, prototypeProperty);
}
AbstractProperty<?> property = this.beanFactory.createProperty(name, null, getBean(), type);
AbstractProperty<?> property = this.beanFactory.createProperty(name, valueType, getBean(), propertyType);
addProperty(property);
return type.cast(property);
return (PROPERTY) property;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,8 @@
import net.sf.mmm.util.bean.api.BeanFactory;
import net.sf.mmm.util.component.base.AbstractLoggableComponent;
import net.sf.mmm.util.property.api.AbstractProperty;
import net.sf.mmm.util.property.api.BooleanProperty;
import net.sf.mmm.util.property.api.GenericProperty;
import net.sf.mmm.util.property.api.IntegerProperty;
import net.sf.mmm.util.property.api.LongProperty;
import net.sf.mmm.util.property.api.ReadableProperty;
import net.sf.mmm.util.property.api.StringProperty;
import net.sf.mmm.util.property.api.WritableProperty;
import net.sf.mmm.util.property.api.factory.PropertyFactory;
import net.sf.mmm.util.property.api.factory.PropertyFactoryManager;
Expand Down Expand Up @@ -221,10 +217,14 @@ public <BEAN extends Bean> BEAN copy(BEAN bean) {
}

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

BeanAccessPrototype<BEAN> prototype = getPrototypeInternal(type);
BeanAccessPrototype<BEAN> copy = new BeanAccessPrototype<>(prototype, dynamic);
String prototypeName = name;
if (prototypeName == null) {
prototypeName = prototype.getName();
}
BeanAccessPrototype<BEAN> copy = new BeanAccessPrototype<>(prototype, dynamic, prototypeName);
return copy.getBean();
}

Expand Down Expand Up @@ -382,43 +382,41 @@ private AbstractProperty<?> createProperty(BeanMethod beanMethod, GenericType<?>
* @param bean the {@link WritableProperty#getBean() property bean}.
* @return the new property instance.
*/
@SuppressWarnings("unchecked")
protected <V> AbstractProperty<V> createProperty(String name, GenericType<V> type, Bean bean) {

return createProperty(name, type, bean, WritableProperty.class);
}

/**
* @param <V> the generic property type.
* @param <PROPERTY> the generic type of the {@link ReadableProperty property}.
* @param name the {@link WritableProperty#getName() property name}.
* @param type the {@link WritableProperty#getType() property type}.
* @param valueType the {@link WritableProperty#getType() property type}.
* @param bean the {@link WritableProperty#getBean() property bean}.
* @param propertyClass the {@link Class} reflecting the {@link WritableProperty} or <code>null</code> if no property
* method exists and this method is called for plain getter or setter.
* @return the new instance of {@link AbstractProperty}.
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
protected <V> AbstractProperty<V> createProperty(String name, GenericType<V> type, Bean bean,
Class<? extends ReadableProperty> propertyClass) {
protected <V, PROPERTY extends ReadableProperty<V>> AbstractProperty<V> createProperty(String name,
GenericType<V> valueType, Bean bean, Class<PROPERTY> propertyClass) {

AbstractProperty result;
PropertyFactory<V, ?> factory = this.propertyFactoryManager.getFactory(propertyClass);
Class<V> valueClass = null;
if (valueType != null) {
valueClass = valueType.getRetrievalClass();
}
PropertyFactory<V, ?> factory = this.propertyFactoryManager.getFactory(propertyClass, valueClass, false);
if (factory != null) {
result = (AbstractProperty) factory.create(name, type, bean, null);
result = (AbstractProperty) factory.create(name, valueType, bean, null);
} else if ((!propertyClass.isInterface()) && (!Modifier.isAbstract(propertyClass.getModifiers()))) {
result = createPropertyFromSpecifiedClass(name, type, bean, propertyClass);
result = createPropertyFromSpecifiedClass(name, valueType, bean, propertyClass);
} else {
Class<?> valueClass = type.getRetrievalClass();
if (valueClass == String.class) {
result = new StringProperty(name, bean);
} else if (valueClass == Boolean.class) {
result = new BooleanProperty(name, bean);
} else if (valueClass == Integer.class) {
result = new IntegerProperty(name, bean);
} else if (valueClass == Long.class) {
result = new LongProperty(name, bean);
} else {
result = new GenericProperty<>(name, type, bean);
}
getLogger().debug(
"Could not resolve specific property for class '{}' and value-type '{}'. Using GenericProperty as fallback.",
propertyClass, valueType);
result = new GenericProperty<>(name, valueType, bean);
}
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@
@ComponentSpecification(plugin = true)
public interface PropertyFactory<V, PROPERTY extends WritableProperty<V>> {

/**
* @return the {@link Class} of the {@link WritableProperty#getValue() property value}. May be <code>null</code> for
* {@link net.sf.mmm.util.property.api.GenericProperty}.
*/
Class<? extends V> getValueClass();

/**
* @return the {@link Class} reflecting the {@link ReadableProperty} interface.
*/
Expand All @@ -43,6 +49,7 @@ public interface PropertyFactory<V, PROPERTY extends WritableProperty<V>> {

/**
* Creates a new instance of the property.
*
* @param name the {@link ReadableProperty#getName() property name}.
* @param valueType is the {@link GenericType} of the value. Only needed for generic properties such as
* {@link net.sf.mmm.util.property.api.GenericProperty} or {@link net.sf.mmm.util.property.api.ListProperty}.
Expand Down
Loading

0 comments on commit 067c928

Please sign in to comment.