StaticFieldAdapter.java
package org.opentrafficsim.xml.bindings;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import org.djutils.reflection.ClassUtil;
import org.opentrafficsim.xml.bindings.types.ExpressionType;
/**
* Superclass for adapters that parse types using static fields, including enums. This class assumes the following to be true
* for the static fields:
* <ul>
* <li>The XML type has values that match the static field names exactly.</li>
* <li>The static field names are present under the type class itself, e.g. {@code Synchronization.PASSIVE} is a
* {@code Synchronization}.</li>
* <li>The type class is either an {@code enum}, or its {@code toString()} method returns the field name, e.g.
* {@code Synchronization.PASSIVE.toString()} gives {@code "PASSIVE"}.</li>
* </ul>
* <p>
* Copyright (c) 2023-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
* BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
* </p>
* @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
* @param <T> value type wrapped in ExpressionType
* @param <E> ExpressionType
*/
public abstract class StaticFieldAdapter<T, E extends ExpressionType<T>> extends ExpressionAdapter<T, E>
{
/** Value type. */
private final Class<T> valueType;
/** Expression type. */
private final Class<E> expressionType;
/**
* Constructor.
* @param valueType Class<T>; value type.
* @param expressionType Class<E>; expression type.
*/
protected StaticFieldAdapter(final Class<T> valueType, final Class<E> expressionType)
{
this.valueType = valueType;
this.expressionType = expressionType;
}
/** {@inheritDoc} */
@Override
public String marshal(final E value)
{
return marshal(value, (t) -> t instanceof Enum ? ((Enum<?>) t).name() : t.toString());
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override
public E unmarshal(final String value) throws IllegalArgumentException
{
try
{
if (isExpression(value))
{
Constructor<E> constructor = ClassUtil.resolveConstructor(this.expressionType, new Class[] {String.class});
return constructor.newInstance(trimBrackets(value));
}
Constructor<E> constructor = ClassUtil.resolveConstructor(this.expressionType, new Class[] {this.valueType});
return constructor.newInstance((T) ClassUtil.resolveField(this.valueType, value).get(null));
}
catch (NoSuchMethodException | InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchFieldException e)
{
throw new IllegalArgumentException("Unable to parse value " + value + " for type " + this.expressionType, e);
}
}
}