net.zerobuilder.compiler.generate.DtoStep Maven / Gradle / Ivy
package net.zerobuilder.compiler.generate;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.TypeName;
import net.zerobuilder.compiler.generate.DtoBeanStep.AbstractBeanStep;
import net.zerobuilder.compiler.generate.DtoParameter.AbstractParameter;
import net.zerobuilder.compiler.generate.DtoParameter.RegularParameter;
import net.zerobuilder.compiler.generate.Utilities.ClassNames;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import static javax.lang.model.element.Modifier.PRIVATE;
import static net.zerobuilder.compiler.generate.DtoBeanStep.validBeanParameter;
import static net.zerobuilder.compiler.generate.Utilities.ClassNames.COLLECTION;
import static net.zerobuilder.compiler.generate.Utilities.ClassNames.ITERABLE;
import static net.zerobuilder.compiler.generate.Utilities.ClassNames.SET;
import static net.zerobuilder.compiler.generate.Utilities.fieldSpec;
import static net.zerobuilder.compiler.generate.Utilities.rawClassName;
import static net.zerobuilder.compiler.generate.Utilities.upcase;
final class DtoStep {
private static final Set LIST_HIERARCHY
= new HashSet<>(Arrays.asList(ClassNames.LIST, COLLECTION, ITERABLE));
static final class EmptyOption {
/**
* Initializer for a variable of type {@link AbstractParameter#type}.
* It evaluates to an empty List or Set.
*/
final CodeBlock initializer;
/**
* Name of the convenience method to be generated, e.g. {@code "emptyFoo"}
*/
final String name;
private EmptyOption(CodeBlock initializer, String name) {
this.initializer = initializer;
this.name = name;
}
static Optional create(TypeName type, String name) {
Optional maybeClassName = rawClassName(type);
if (!maybeClassName.isPresent()) {
return Optional.empty();
}
ClassName className = maybeClassName.get();
if (LIST_HIERARCHY.contains(className)) {
return Optional.of(new EmptyOption(
CodeBlock.of("$T.emptyList()", Collections.class),
emptyOptionName(name)));
}
if (SET.equals(className)) {
return Optional.of(new EmptyOption(
CodeBlock.of("$T.emptySet()", Collections.class),
emptyOptionName(name)));
}
return Optional.empty();
}
private static String emptyOptionName(String name) {
return "empty" + upcase(name);
}
}
static abstract class AbstractStep {
final ClassName thisType;
final TypeName nextType;
AbstractStep(ClassName thisType, TypeName nextType) {
this.thisType = thisType;
this.nextType = nextType;
}
abstract R accept(StepCases cases);
}
interface StepCases {
R regularStep(RegularStep step);
R beanStep(AbstractBeanStep step);
}
static Function asFunction(final StepCases cases) {
return abstractStep -> abstractStep.accept(cases);
}
static StepCases stepCases(final Function super RegularStep, R> regularFunction,
final Function super AbstractBeanStep, R> beanFunction) {
return new StepCases() {
@Override
public R regularStep(RegularStep step) {
return regularFunction.apply(step);
}
@Override
public R beanStep(AbstractBeanStep step) {
return beanFunction.apply(step);
}
};
}
static final class RegularStep extends AbstractStep {
final RegularParameter validParameter;
final List declaredExceptions;
private RegularStep(ClassName thisType, TypeName nextType, RegularParameter validParameter,
List declaredExceptions) {
super(thisType, nextType);
this.declaredExceptions = declaredExceptions;
this.validParameter = validParameter;
}
static RegularStep create(ClassName thisType, TypeName nextType, RegularParameter parameter,
List declaredExceptions) {
return new RegularStep(thisType, nextType, parameter, declaredExceptions);
}
Optional emptyOption() {
return EmptyOption.create(validParameter.type, validParameter.name);
}
FieldSpec field() {
return fieldSpec(validParameter.type, validParameter.name, PRIVATE);
}
@Override
R accept(StepCases cases) {
return cases.regularStep(this);
}
}
static final Function abstractParameter
= asFunction(new StepCases() {
@Override
public AbstractParameter regularStep(RegularStep step) {
return step.validParameter;
}
@Override
public AbstractParameter beanStep(AbstractBeanStep step) {
return step.acceptBean(validBeanParameter);
}
});
static final Function> declaredExceptions
= asFunction(new StepCases>() {
@Override
public List regularStep(RegularStep step) {
return step.declaredExceptions;
}
@Override
public List beanStep(AbstractBeanStep step) {
return Collections.emptyList();
}
});
static Function always(final Function parameterFunction) {
return asFunction(new StepCases() {
@Override
public R regularStep(RegularStep step) {
return parameterFunction.apply(step);
}
@Override
public R beanStep(AbstractBeanStep step) {
return parameterFunction.apply(step);
}
});
}
static final Function> emptyOption
= asFunction(new StepCases>() {
@Override
public Optional regularStep(RegularStep step) {
return step.emptyOption();
}
@Override
public Optional beanStep(AbstractBeanStep step) {
return step.acceptBean(DtoBeanStep.emptyOption);
}
});
private DtoStep() {
throw new UnsupportedOperationException("no instances");
}
}