au.net.causal.projo.prefs.transform.FloatingPointCastTransformer Maven / Gradle / Ivy
Show all versions of projo Show documentation
package au.net.causal.projo.prefs.transform;
import java.math.BigDecimal;
import java.util.List;
import au.net.causal.projo.prefs.DataTypeSupport;
import au.net.causal.projo.prefs.PreferenceKeyMetadata;
import au.net.causal.projo.prefs.PreferencesException;
import au.net.causal.projo.prefs.TransformDataTypeSupportChain;
import au.net.causal.projo.prefs.TransformGetChain;
import au.net.causal.projo.prefs.TransformPutChain;
import au.net.causal.projo.prefs.TransformRemoveChain;
import au.net.causal.projo.prefs.TransformResult;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.primitives.Primitives;
/**
* Transforms between floating point numeric data types to fit the native store. This is useful when a store only supports a larger data type but support is needed
* for the smaller ones.
*
*
* For example, if the native store supports {@link Double}s, then this transformer will add support for the smaller numeric {@link Float}
* performing numeric conversions where appropriate.
*
* @author prunge
*/
public class FloatingPointCastTransformer implements PreferenceTransformer
{
private final List> dataTypes = ImmutableList.>of(BigDecimal.class, Double.class, Float.class);
@Override
public TransformResult applyGet(String key, PreferenceKeyMetadata keyMetadata, TransformGetChain chain)
throws PreferencesException
{
Class extends Number> bestMatch = findClosestNativeSupportForDataType(keyMetadata, chain);
if (bestMatch == null)
return(null);
Number nValue = chain.getValue(key, keyMetadata.withDataType(bestMatch));
if (nValue == null)
return(new TransformResult<>(null));
Class extends Number> keyType = Primitives.wrap(keyMetadata.getDataType().getRawType()).asSubclass(Number.class);
//Need to convert the native value nValue to key's data type
if (BigDecimal.class.equals(keyType))
return(new TransformResult<>((T)BigDecimal.valueOf(nValue.doubleValue())));
else if (Double.class.equals(keyType))
return(new TransformResult<>((T)Double.valueOf(nValue.doubleValue())));
else if (Float.class.equals(keyType))
return(new TransformResult<>((T)Float.valueOf(nValue.floatValue())));
else ///Should never get here
throw new Error("Unknokwn bestMatch data type.");
}
@Override
public boolean applyPut(String key, T value, PreferenceKeyMetadata keyMetadata, TransformPutChain chain)
throws PreferencesException
{
Class extends Number> bestMatch = findClosestNativeSupportForDataType(keyMetadata, chain);
if (bestMatch == null)
return(false);
Number nValue = (Number)value;
if (nValue == null)
chain.putValue(key, null, keyMetadata.withDataType(bestMatch));
else if (BigDecimal.class.equals(bestMatch))
chain.putValue(key, BigDecimal.valueOf(nValue.doubleValue()), keyMetadata.withDataType(BigDecimal.class));
else if (Double.class.equals(bestMatch))
chain.putValue(key, Double.valueOf(nValue.doubleValue()), keyMetadata.withDataType(Double.class));
else if (Float.class.equals(bestMatch))
chain.putValue(key, Float.valueOf(nValue.floatValue()), keyMetadata.withDataType(Float.class));
else ///Should never get here
throw new Error("Unknokwn bestMatch data type.");
return(true);
}
@Override
public boolean applyRemove(String key, PreferenceKeyMetadata keyMetadata, TransformRemoveChain chain)
throws PreferencesException
{
Class extends Number> bestMatch = findClosestNativeSupportForDataType(keyMetadata, chain);
if (bestMatch == null)
return(false);
chain.removeValue(key, keyMetadata.withDataType(bestMatch));
return(true);
}
@Override
public DataTypeSupport applyDataTypeSupport(PreferenceKeyMetadata> keyMetadata, TransformDataTypeSupportChain chain)
throws PreferencesException
{
//If not a numeric data type then no support from this transformer
Class extends Number> bestMatch = findClosestNativeSupportForDataType(keyMetadata, chain);
if (bestMatch == null)
return(null);
//If we get here the transform will work
return(DataTypeSupport.ADD_SUPPORT);
}
private Class extends Number> findClosestNativeSupportForDataType(PreferenceKeyMetadata> keyMetadata, TransformDataTypeSupportChain chain)
throws PreferencesException
{
Class> keyType = keyMetadata.getDataType().getRawType();
keyType = Primitives.wrap(keyType);
int dataTypeIndex = dataTypes.indexOf(keyType);
if (dataTypeIndex < 0)
return(null);
//If there is native support for the key type itself then this transform shouldn't touch it
if (chain.isDataTypeSupportedNatively(keyMetadata.withDataType(keyType))) //Normalized data type
return(null);
//Find the next biggest data type supported natively
List> supportForKey = dataTypes.subList(0, dataTypeIndex + 1);
supportForKey = Lists.reverse(supportForKey);
//Now supportForKey contains all data types that can support the key type, ordered from closest match up to largest data type
//Go through and ask for native support until we find one
for (Class extends Number> curDataType : supportForKey)
{
if (chain.isDataTypeSupportedNatively(keyMetadata.withDataType(curDataType)))
return(curDataType);
}
return(null);
}
}