All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fr.vergne.pester.definition.PojoDefinition Maven / Gradle / Ivy

The newest version!
package fr.vergne.pester.definition;

import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import fr.vergne.pester.factory.Factory;
import fr.vergne.pester.junit.annotation.ConstructorPropertiesHelper;
import fr.vergne.pester.options.Visibility;
import fr.vergne.pester.util.cache.Cache;
import fr.vergne.pester.util.cache.Key;
import fr.vergne.pester.util.cache.ParameteredKey;
import fr.vergne.pester.util.observer.OccurrenceObserver;
import fr.vergne.pester.value.Generator;
import fr.vergne.pester.value.Type;

public class PojoDefinition

{ private final Factory factory; private final Class

pojoClass; private Optional> parentClass = Optional.empty(); private final Collection> interfaces = new LinkedHashSet<>(); private final Optional> pojoGenerator; private final Map> properties; private final Map>, ConstructorDefinition

> constructors; /** Used only if no generator is set and no valid constructor is found */ private final NullPointerException nullPojoGeneratorException; private final Cache cache = Cache.create(); public PojoDefinition(Class

pojoClass) { this(pojoClass, new Factory()); } public PojoDefinition(Class

pojoClass, Factory factory) { this(pojoClass, Optional.empty(), factory); } public PojoDefinition(Generator

pojoGenerator) { this(pojoGenerator, new Factory()); } @SuppressWarnings("unchecked") public PojoDefinition(Generator

pojoGenerator, Factory factory) { this((Class

) pojoGenerator.create().getClass(), Optional.of(pojoGenerator), factory); } public PojoDefinition(Class

pojoClass, Generator

pojoGenerator) { this(pojoClass, Optional.of(pojoGenerator), new Factory()); } private PojoDefinition(Class

pojoClass, Optional> optional, Factory factory) { this.pojoClass = pojoClass; this.properties = new LinkedHashMap<>(); this.constructors = new LinkedHashMap<>(); this.pojoGenerator = optional; this.nullPojoGeneratorException = new NullPointerException("No Pojo generator set, set one or add constructors"); this.factory = factory; } public Factory create() { return factory; } // POJO public Class

getPojoClass() { return pojoClass; } public void setParentClass(Class parentClass) { if (parentClass.isInterface()) { throw new InterfaceClassException(parentClass); } else { this.parentClass = Optional.of(parentClass); } } public Optional> getParentClass() { return parentClass; } public void addInterfaces(Class... interfaceClasses) { Optional> nonInterfaceClass = Stream.of(interfaceClasses) .filter(interfaceClass -> !interfaceClass.isInterface()) .findAny(); if (nonInterfaceClass.isPresent()) { throw new NonInterfaceClassException(nonInterfaceClass.get()); } else { interfaces.addAll(Arrays.asList(interfaceClasses)); } } public Collection> getInterfaces() { return interfaces; } private final Key> pojoGeneratorKey = ParameteredKey.create(new Object()); public Generator

getPojoGenerator() { return pojoGenerator.orElseGet(() -> cache.get(pojoGeneratorKey, this::createPojoGeneratorFromConstructors)); } private Generator

createPojoGeneratorFromConstructors() { return () -> { OccurrenceObserver generatorException = new OccurrenceObserver<>(); OccurrenceObserver invalidConstructorException = new OccurrenceObserver<>(); Optional

pojo = getConstructors().stream() .sorted(Comparator.comparing(constructor -> constructor.getParametersDefinitions().size())) .map(definition -> { List parameters; try { parameters = definition.getParametersGenerator().create(); } catch (Exception cause) { generatorException.occurs(cause); return null; } fr.vergne.pester.model.Constructor

constructor = definition.getInstance(); try { return constructor.invoke(parameters); } catch (Exception cause) { invalidConstructorException.occurs(new ConstructorCannotGeneratePojoException(cause)); return null; } }) .filter(Objects::nonNull) .findAny(); if (pojo.isPresent()) { return pojo.get(); } else if (generatorException.hasOccurred()) { throw new PojoGeneratorNotFoundException(generatorException.getFirstOccurrence()); } else if (invalidConstructorException.hasOccurred()) { throw new PojoGeneratorNotFoundException(invalidConstructorException.getFirstOccurrence()); } else { throw new PojoGeneratorNotFoundException(nullPojoGeneratorException); } }; } // CONSTRUCTORS @SafeVarargs public final ConstructorDefinition

addConstructor(Visibility visibility, PropertyDefinition... parameters) { return addConstructor(Optional.of(visibility), parameters); } @SafeVarargs public final ConstructorDefinition

addConstructor(PropertyDefinition... parameters) { return addConstructor(Optional.empty(), parameters); } @SafeVarargs private final ConstructorDefinition

addConstructor(Optional visibility, PropertyDefinition... parameters) { List> params = Arrays.asList(parameters); List> types = params.stream().map(PropertyDefinition::getType).collect(Collectors.toList()); return addConstructor(visibility, params, types); } private ConstructorDefinition

addConstructor(Optional visibility, List> params, List> types) { return (ConstructorDefinition

) constructors.compute(types, (k, previousDefinition) -> { if (previousDefinition == null) { return new ConstructorDefinition<>(pojoClass, params, visibility); } else { throw new IllegalArgumentException("Already defined constructor on " + types); } }); } public Collection> getConstructors() { return constructors.values(); } // PROPERTIES public PropertyDefinition addProperty(Class typeClass) { return addProperty(factory.type().from(typeClass)); } public PropertyDefinition addProperty(Type type) { return addProperty(type, Optional.empty()); } PropertyDefinition addProperty(Class typeClass, Optional name) { return addProperty(factory.type().from(typeClass), name); } private long unnamedFieldIndex = 0; private final Supplier autoFieldNamer = () -> "?"+(++unnamedFieldIndex); PropertyDefinition addProperty(Type type, Optional name) { return addProperty(type, name.orElseGet(autoFieldNamer)); } public PropertyDefinition addProperty(Class typeClass, String name) { return addProperty(factory.type().from(typeClass), name); } @SuppressWarnings("unchecked") public PropertyDefinition addProperty(Type type, String name) { if (name.equals(ConstructorPropertiesHelper.NON_PROPERTY)) { return addProperty(type); } else { return (PropertyDefinition) properties.compute(name, (k, previousDefinition) -> { if (previousDefinition == null) { return new PropertyDefinition<>(pojoClass, name, type); } else { throw new AlreadyDefinedPropertyException(name); } }); } } public Collection> getProperties() { return properties.values(); } @SuppressWarnings("serial") private static class PojoGeneratorNotFoundException extends RuntimeException { public PojoGeneratorNotFoundException(Throwable cause) { super("No valid POJO generator found", cause); } } @SuppressWarnings("serial") private static class ConstructorCannotGeneratePojoException extends RuntimeException { public ConstructorCannotGeneratePojoException(Throwable cause) { super("Cannot use constructor as POJO generator", cause); } } @SuppressWarnings("serial") private static class InterfaceClassException extends RuntimeException { public InterfaceClassException(Class interfaceClass) { super("Not a class, but an interface: " + interfaceClass); } } @SuppressWarnings("serial") private static class NonInterfaceClassException extends RuntimeException { public NonInterfaceClassException(Class nonInterfaceClass) { super("Not an interface: " + nonInterfaceClass); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy