net.zerobuilder.compiler.generate.DtoGoalDescription Maven / Gradle / Ivy
package net.zerobuilder.compiler.generate;
import com.squareup.javapoet.TypeName;
import net.zerobuilder.compiler.generate.DtoBeanParameter.AbstractBeanParameter;
import net.zerobuilder.compiler.generate.DtoGoal.AbstractGoalDetails;
import net.zerobuilder.compiler.generate.DtoGoal.BeanGoalDetails;
import net.zerobuilder.compiler.generate.DtoGoal.RegularGoalDetails;
import net.zerobuilder.compiler.generate.DtoParameter.RegularParameter;
import java.util.List;
import java.util.function.Function;
public final class DtoGoalDescription {
public interface GoalDescription {
R accept(GoalDescriptionCases cases);
}
interface GoalDescriptionCases {
R regularGoal(RegularGoalDescription goal);
R beanGoal(BeanGoalDescription goal);
}
static Function asFunction(final GoalDescriptionCases cases) {
return goal -> goal.accept(cases);
}
/**
* Describes of a goal that represents either a static method or an instance method, or a constructor.
*/
public static final class RegularGoalDescription implements GoalDescription {
final RegularGoalDetails details;
final List thrownTypes;
final List parameters;
private RegularGoalDescription(RegularGoalDetails details,
List thrownTypes,
List parameters) {
this.details = details;
this.thrownTypes = thrownTypes;
this.parameters = parameters;
}
/**
* @param details goal details
* @param thrownTypes exceptions thrown by the goal method, if any
* @param parameters parameter names, possibly in a different order;
* must contain each parameter name in {@link RegularGoalDetails#parameterNames}
* exactly once
* @return goal description
* @throws IllegalArgumentException if {@code parameters} don't match the parameter names in {@code details}
*/
public static RegularGoalDescription create(RegularGoalDetails details,
List thrownTypes,
List parameters) {
checkParameterNames(details.parameterNames, parameters);
validateProjectionInfo(details.goalOptions, parameters);
return new RegularGoalDescription(details, thrownTypes, parameters);
}
private static void validateProjectionInfo(DtoGoal.GoalOptions options,
List parameters) {
if (!options.toBuilder) {
return;
}
if (parameters.stream()
.map(parameter -> parameter.projectionInfo)
.allMatch(DtoProjectionInfo.isPresent)) {
return;
}
throw new IllegalStateException("projection info required");
}
private static void checkParameterNames(List parameterNames,
List parameters) {
if (parameters.isEmpty()) {
throw new IllegalArgumentException("need at least one parameter");
}
if (parameterNames.size() != parameters.size()) {
throw new IllegalArgumentException("parameter names mismatch");
}
int[] positions = new int[parameterNames.size()];
for (RegularParameter parameter : parameters) {
int i = parameterNames.indexOf(parameter.name);
if (positions[i]++ != 0) {
throw new IllegalArgumentException("parameter names mismatch");
}
}
}
@Override
public R accept(GoalDescriptionCases cases) {
return cases.regularGoal(this);
}
}
/**
* Describes the task of creating and / or updating a JavaBean.
*/
public static final class BeanGoalDescription implements GoalDescription {
final BeanGoalDetails details;
final List parameters;
private BeanGoalDescription(BeanGoalDetails details, List parameters) {
this.details = details;
this.parameters = parameters;
}
public static BeanGoalDescription create(BeanGoalDetails details, List parameters) {
return new BeanGoalDescription(details, parameters);
}
@Override
public R accept(GoalDescriptionCases cases) {
return cases.beanGoal(this);
}
}
private static final Function abstractGoal =
asFunction(new GoalDescriptionCases() {
@Override
public AbstractGoalDetails regularGoal(RegularGoalDescription goal) {
return goal.details;
}
@Override
public AbstractGoalDetails beanGoal(BeanGoalDescription goal) {
return goal.details;
}
});
static String goalName(GoalDescription goal) {
return abstractGoal.apply(goal).name;
}
static TypeName goalType(GoalDescription goal) {
return DtoGoal.goalType.apply(DtoGoalDescription.abstractGoal.apply(goal));
}
private DtoGoalDescription() {
throw new UnsupportedOperationException("no instances");
}
}