package com.cedarsoft.spring.rcp.creation;
import com.cedarsoft.spring.rcp.PropertyPath;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.AbstractPropertyAccessor;
import org.springframework.beans.BeansException;
import org.springframework.beans.NotWritablePropertyException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.core.MethodParameter;
import java.util.HashMap;
import java.util.Map;
/**
* A special property accessor that works on a map
*/
public class MappedPropertyAccessor extends AbstractPropertyAccessor {
@NotNull
private final Map<String, Object> values = new HashMap<String, Object>();
@NotNull
private final Map<String, Class<?>> registeredTypes = new HashMap<String, Class<?>>();
@NotNull
private final Class<?> beanType;
public MappedPropertyAccessor( @NotNull Class<?> beanType ) {
this.beanType = beanType;
}
@Override
public boolean isReadableProperty( @NotNull @NonNls String propertyName ) {
return registeredTypes.containsKey( propertyName );
}
@Override
public Class<?> getPropertyType( @NotNull @NonNls String propertyPath ) {
verifyRegistered( propertyPath );
return registeredTypes.get( propertyPath );
}
private void verifyRegistered( @NotNull @NonNls String propertyPath ) {
Class<?> propertyType = registeredTypes.get( propertyPath );
if ( propertyType == null ) {
@NonNls
String extendedPropertyPath = propertyPath + '.';
//Check whether we have at least one that start with the property path
for ( String key : registeredTypes.keySet() ) {
if ( key.startsWith( extendedPropertyPath ) ) {
return;
}
}
throw new NotWritablePropertyException( this.beanType, propertyPath );
}
}
@Override
public boolean isWritableProperty( @NotNull @NonNls String propertyName ) {
return registeredTypes.containsKey( propertyName );
}
@Override
public Object getPropertyValue( @NotNull @NonNls String propertyName ) throws BeansException {
verifyRegistered( propertyName );
return values.get( propertyName );
}
@Override
public void setPropertyValue( @NotNull @NonNls String propertyName, Object value ) throws BeansException {
verifyType( propertyName, value );
values.put( propertyName, value );
}
private void verifyType( @NotNull @NonNls String propertyName, @Nullable Object value ) throws BeansException {
Class<?> propertyType = getPropertyType( propertyName );
if ( value == null ) {
return;
}
if ( !propertyType.isAssignableFrom( value.getClass() ) ) {
throw new TypeMismatchException( value, propertyType );
}
}
public void registerProperty( @NotNull Class<?> propertyType, @NotNull @NonNls PropertyPath propertyPath ) {
registerProperty( propertyType, propertyPath.getProperty() );
}
public void registerProperty( @NotNull Class<?> propertyType, @NotNull @NonNls String propertyName ) {
if ( propertyName.length() == 0 ) {
throw new IllegalArgumentException( "Invalid property name. Need at least one character." );
}
registeredTypes.put( propertyName, propertyType );
}
@Override
public Object convertIfNecessary( Object value, Class requiredType, MethodParameter methodParam ) throws TypeMismatchException {
throw new UnsupportedOperationException();
}
}