package co.codewizards.cloudstore.core.objectfactory;
import java.util.ServiceLoader;
/**
* Simple API to use the {@link ObjectFactory}.
* <p>
* Devs should add the following import:
* <pre>
* import static co.codewizards.cloudstore.core.objectfactory.ObjectFactoryUtil.*;
* </pre>
* They can then invoke one of the {@code createObject(...)} methods simply without any prefix.
* <p>
* In order to register a sub-class as replacement for a certain base-class, implementors have to provide a
* {@link ClassExtension} and register it using the {@link ServiceLoader}-mechanism.
* <p>
* <b>Important:</b> If a certain base-class should be replaceable using this mechanism, <b>all</b> occurrences
* of {@code new MyBaseClass(...)} in the entire code-base must be replaced by {@code createObject(MyBaseClass.class, ...)}.
* <p>
* <b>Important 2:</b> It is urgently recommended <i>not</i> to use this approach, whenever it is possible to use a better solution,
* preferably a well-defined service (=> {@link ServiceLoader}). There are situations, though, e.g. data-model-classes
* (a.k.a. entities), where services are not possible and {@code ObjectFactoryUtil} + {@code ClassExtension} is the perfect solution.
* <p>
*
* @author Marco หงุ่ยตระกูล-Schulze - marco at codewizards dot co
*/
public class ObjectFactoryUtil {
protected ObjectFactoryUtil() { }
/**
* Create an instance of the given class or a sub-class registered as replacement.
* <p>
* If at least one {@link ClassExtension} is registered for the given class, the {@code ClassExtension}
* with the highest {@link ClassExtension#getPriority() priority} is chosen and its
* {@link ClassExtension#getExtendingClass() extendingClass} instantiated instead of the base-class passed as {@code clazz}.
* <p>
* This method always invokes the default constructor (without any parameters).
* @param clazz the base-class to be instantiated. Must not be <code>null</code>.
* @return the object instantiated either from the given base-class or a sub-class registered via {@link ClassExtension}.
* Never <code>null</code>.
* @see #createObject(Class, Class[], Object...)
*/
public static <T> T createObject(final Class<T> clazz) {
return ObjectFactory.getInstance().createObject(clazz);
}
/**
* Create an instance of the given class or a sub-class registered as replacement.
* <p>
* If at least one {@link ClassExtension} is registered for the given class, the {@code ClassExtension}
* with the highest {@link ClassExtension#getPriority() priority} is chosen and its
* {@link ClassExtension#getExtendingClass() extendingClass} instantiated instead of the base-class passed as {@code clazz}.
* <p>
* This method tries to automatically find the best constructor matching the given parameters.
* If multiple constructors might match and they are not semantically the same (only doing some implicit conversions),
* you should instead use {@link #createObject(Class, Class[], Object...)} and pass the specific parameter types.
* @param clazz the base-class to be instantiated. Must not be <code>null</code>.
* @param parameters the parameters to be passed to the constructor.
* @return the object instantiated either from the given base-class or a sub-class registered via {@link ClassExtension}.
* Never <code>null</code>.
* @see #createObject(Class, Class[], Object...)
*/
public static <T> T createObject(final Class<T> clazz, final Object ... parameters) {
return ObjectFactory.getInstance().createObject(clazz, (Class<?>[]) null, parameters);
}
/**
* Create an instance of the given class or a sub-class registered as replacement.
* <p>
* If at least one {@link ClassExtension} is registered for the given class, the {@code ClassExtension}
* with the highest {@link ClassExtension#getPriority() priority} is chosen and its
* {@link ClassExtension#getExtendingClass() extendingClass} instantiated instead of the base-class passed as {@code clazz}.
* <p>
* This method invokes the constructor matching exactly the given parameter-types. If {@code parameterTypes} is
* <code>null</code>, a matching constructor is searched automatically based on the concrete {@code parameters}.
*
* @param clazz the base-class to be instantiated. Must not be <code>null</code>.
* @param parameterTypes either <code>null</code> or the exact argument-types of the constructor to be invoked.
* @param parameters the parameters to be passed to the constructor.
* @return the object instantiated either from the given base-class or a sub-class registered via {@link ClassExtension}.
* Never <code>null</code>.
*/
public static <T> T createObject(final Class<T> clazz, final Class<?>[] parameterTypes, final Object ... parameters) {
return ObjectFactory.getInstance().createObject(clazz, parameterTypes, parameters);
}
public static <T> Class<? extends T> getExtendingClass(final Class<T> clazz) {
return ObjectFactory.getInstance().getExtendingClass(clazz);
}
}