/* * Copyright (c) 2017 OBiBa. All rights reserved. * * This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.obiba.magma; import java.io.Serializable; import java.util.Comparator; import javax.annotation.Nullable; import javax.validation.constraints.NotNull; /** * Provides a common interface for all types of values available in the {@code MagmaEngine}. Through this interface, * callers may obtain information on the type's nature, obtain {@code Value} instances from Java objects and convert * values to a stable string representation (and back). */ public interface ValueType extends Serializable, Comparator<Value> { /** * Provides access to all {@code ValueType} instances by name or Java type. Also allows creating {@code Value} * instances from Java objects. */ final class Factory { private Factory() { } /** * Returns the {@code ValueType} instance for the specified {@code name}. * * @param name the unique name of the {@code ValueType} instance * @return the {@code ValueType} instance for the specified {@code name} * @throws IllegalArgumentException when no type exists for the specified name */ public static ValueType forName(@Nullable String name) throws IllegalArgumentException { return MagmaEngine.get().getValueTypeFactory().forName(name); } /** * Returns the {@code ValueType} instance that accepts the specified java {@code Class}, as specified by the * {@link ValueType#acceptsJavaClass(Class)} method. * * @param javaClass the Java {@code Class} to test * @return the {@code ValueType} instance that accepts the specified {@code Class}. * @throws IllegalArgumentException when no type exists for the specified class */ public static ValueType forClass(Class<?> javaClass) throws IllegalArgumentException { return MagmaEngine.get().getValueTypeFactory().forClass(javaClass); } /** * Returns a new {@code Value} instance for the specified object instance. This method will determine the proper * {@code ValueType} by passing the object's class to the {@link #forClass(Class)} method. Note that this method * does not accept {@code null} as it would be impossible to determine the {@code ValueType} of the returned * {@code Value}. * * @param value the object instance for which to obtain a {@code Value} instance. Cannot be null. * @return a {@code Value} instance for the specified object. * @throws IllegalArgumentException when {@code value} is null. */ @SuppressWarnings("ConstantConditions") @NotNull public static Value newValue(@NotNull Serializable value) { if(value == null) { throw new IllegalArgumentException("cannot determine ValueType for null object"); } return forClass(value.getClass()).valueOf(value); } @NotNull public static Value newValue(@NotNull ValueType type, @Nullable Serializable value) { return new Value(type, value); } @NotNull public static Value newValue(@NotNull ValueType type, @Nullable ValueLoader valueLoader) { return new Value(type, valueLoader); } @NotNull public static ValueSequence newSequence(@NotNull ValueType type, @Nullable Iterable<Value> values) { return new ValueSequence(type, values); } @NotNull public static ValueConverter converterFor(ValueType from, ValueType to) { return MagmaEngine.get().getValueTypeFactory().converterFor(from, to); } } /** * The unique name of this {@code ValueType}. * * @return this type's unique name */ @NotNull String getName(); /** * The java class of the value held in a {@code Value} instance of this {@code ValueType}. That is, when a * {@code Value} instance if of this {@code ValueType}, the contained object should be of the type returned by this * method. * * @return the normalized java class for this {@code ValueType} */ Class<?> getJavaClass(); /** * Returns true if an instance of the specified class is suitable for invoking the {@link #valueOf(Object)} method. * * @param clazz the type to check * @return true if the {@link #valueOf(Object)} can be called with an instance of the specified class. */ boolean acceptsJavaClass(@NotNull Class<?> clazz); /** * Returns true if this type represents a date, time or both. * * @return if this type represents a date, time or both. */ boolean isDateTime(); /** * Returns true if this type represents a number. * * @return true if this type represents a number */ boolean isNumeric(); /** * Returns true if this type represents a geolocalisation. * * @return true if this type represents a geolocalisation */ boolean isGeo(); /** * Returns true if this type represents a binary. * * @return true if this type represents a binary */ boolean isBinary(); /** * Returns a {@code Value} instance that represents the null value for this type. Calling {@link Value#isNull()} on * the returned instance will return true. * * @return a {@code Value} instance for null. */ @NotNull Value nullValue(); /** * Returns a {@code ValueSequence} instance that represents the null value for this type. Calling * {@link Value#isNull()} on the returned instance will return true. * * @return a {@code ValueSequence} instance for null */ @NotNull ValueSequence nullSequence(); /** * Given a {@code Value} instance, this method will make a best efforts process to convert the underlying value from * its original {@code ValueType} to this {@code ValueType}. * <p/> * Simple cases (no conversion required or null values) are handled directly. Any other case is delegated to an * instance of {@code ValueConverter}. * * @param value the value to convert * @return a {@code Value} instance of this {@code ValueType} */ @NotNull Value convert(@NotNull Value value); /** * Returns a string representation of the {@code value}. The string returned can be passed to the * {@link #valueOf(String)} method which should return an equivalent {@code Value} instance. * * @param value the value to convert to a string * @return a {@code String} representation of the {@code value}. */ @Nullable String toString(@Nullable Value value); /** * Converts a string representation of a {@code value} to a {@code Value} instance. The string representation should * match the expected format which is specified by the {@link #toString(Value)} method. * * @param string a string representation of the value. May be null, in which case, the returned value is that of * calling {@link #nullValue()} * @return a {@code Value} instance after converting its string representation. */ @NotNull Value valueOf(@Nullable String string); /** * Builds a {@code Value} instance after converting the specified object to the normalized type returned by * {@link #getJavaClass()} method. Note that this method accepts null values and should return a non-null * {@code Value} instance. * <p/> * For example, this method would convert instances of {@code java.util.Date}, {@code java.sql.Date}, * {@code java.sql.Timestamp}, {@code java.util.Calendar} to an instance of {@code java.util.Date} and return a * {@code Value} instance containing the normalized instance. * * @param object the instance to normalize. May be null, in which case, the returned value is that of calling * {@link #nullValue()} * @return a {@code Value} instance for the specified object. */ @NotNull Value valueOf(@Nullable Object object); @NotNull Value valueOf(@Nullable ValueLoader loader); /** * Returns a {@code ValueSequence} instance containing the specified {@code values}. * * @param values the sequence of {@code Value} instances to hold in the {@code ValueSequence}. May be null, in which * case, the return value is that of calling {@link #nullSequence()} * @return a {@code ValueSequence} instance containing {@code values} */ @NotNull ValueSequence sequenceOf(@Nullable Iterable<Value> values); @NotNull ValueSequence sequenceOf(@Nullable String values); }