package jalse.entities.functions; import static jalse.entities.Entities.isEntitySubtype; import static jalse.entities.functions.Functions.checkHasReturnType; import static jalse.entities.functions.Functions.checkNotDefault; import java.lang.reflect.Method; import java.util.UUID; import java.util.function.Supplier; import jalse.attributes.AttributeContainer; import jalse.entities.DefaultEntityProxyFactory; import jalse.entities.Entity; import jalse.entities.EntityContainer; import jalse.entities.annotations.EntityID; import jalse.entities.annotations.NewEntity; import jalse.entities.methods.NewEntityMethod; /** * This is a method function for {@link NewEntity} annotation. It will resolve an * {@link NewEntityMethod} to be used by the entity typing system.<br> * <br> * The next example signatures will resolve to {@link EntityContainer#newEntity()}. * * <pre> * <code> * {@code @NewEntity} * Ghost newGhost(); * * {@code @EntityID(random = true)} * {@code @NewEntity} * Ghost newGhost(); * </code> * </pre> * * The next example signatures will resolve to {@link EntityContainer#newEntity(java.util.UUID)}. * * <pre> * <code> * {@code @NewEntity} * Ghost newGhost(UUID id); * * {@code @EntityID(mostSigBits = 0, leastSigBits = 1)} * {@code @NewEntity} * Ghost newGhost(); * </code> * </pre> * * The next example signatures will resolve to * {@link EntityContainer#newEntity(java.util.UUID, AttributeContainer)}. * * <pre> * <code> * {@code @NewEntity} * Ghost newGhost(UUID id, AttributeContainer container); * * {@code @EntityID(mostSigBits = 0, leastSigBits = 1)} * {@code @NewEntity} * Ghost newGhost(AttributeContainer container); * </code> * </pre> * * The next example signatures will resolve to {@link EntityContainer#newEntity(AttributeContainer)} * . * * <pre> * <code> * {@code @NewEntity} Ghost newGhost(AttributeContainer container); * * {@code @EntityID(random = true)} * {@code @NewEntity} * Ghost newGhost(AttributeContainer container); * </code> * </pre> * * NOTE: This function will throw exceptions if {@link NewEntity} is present but the method * signature is invalid. * * @author Elliot Ford * * @see DefaultEntityProxyFactory * */ public class NewEntityFunction implements EntityMethodFunction { @SuppressWarnings("unchecked") @Override public NewEntityMethod apply(final Method m) { // Check for annotation final NewEntity annonation = m.getAnnotation(NewEntity.class); if (annonation == null) { return null; } // Basic check method signature checkHasReturnType(m); checkNotDefault(m); if (m.getParameterCount() > 2) { throw new IllegalArgumentException("Cannot have over two params"); } // Check return type final Class<?> returnType = m.getReturnType(); if (!Entity.class.equals(returnType) && !isEntitySubtype(returnType)) { throw new IllegalArgumentException("Return type must be entity or type descendant"); } // Get and validate ID final Supplier<UUID> idSupplier = Functions.getSingleIDSupplier(m); // Work out method type final Class<?>[] params = m.getParameterTypes(); // Duplicate ID defintiion if (params.length >= 1 && UUID.class.equals(params[0]) && idSupplier != null) { throw new IllegalArgumentException(String.format("Cannot have %s annotation and ID param", EntityID.class)); } // If one param must be ID or container if (params.length == 1 && !UUID.class.equals(params[0]) && !AttributeContainer.class.equals(params[0])) { throw new IllegalArgumentException("To have one param it must be ID or container"); } // If two params must be ID and container if (params.length == 2 && (!UUID.class.equals(params[0]) || !AttributeContainer.class.equals(params[1]))) { throw new IllegalArgumentException("To have two params they must be ID and container"); } // Wether it is a container method final boolean idParam = params.length == 2 || params.length == 1 && UUID.class.equals(params[0]); final boolean containerParam = params.length == 2 || params.length == 1 && AttributeContainer.class.equals(params[0]); // Create new entity method final NewEntityMethod nem = new NewEntityMethod((Class<? extends Entity>) returnType); nem.setRequiresIDParam(idParam); nem.setRequiresContainerParam(containerParam); if (!idParam) { nem.setIDSupplier(idSupplier); } return nem; } }