org.neo4j.codegen.MethodTemplate Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of neo4j-codegen Show documentation
Show all versions of neo4j-codegen Show documentation
Simple library for generating code.
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [https://neo4j.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package org.neo4j.codegen;
import static java.util.Objects.requireNonNull;
import static org.neo4j.codegen.Parameter.NO_PARAMETERS;
import static org.neo4j.codegen.TypeReference.NO_TYPES;
import static org.neo4j.codegen.TypeReference.typeReference;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MethodTemplate {
public static Builder method(Class> returnType, String name, Parameter... parameters) {
return method(typeReference(returnType), name, parameters);
}
public static Builder method(final TypeReference returnType, final String name, Parameter... parameters) {
try {
return new Builder(parameters) {
@Override
public MethodTemplate build() {
return buildMethod(this, returnType, name);
}
@Override
MethodDeclaration.Builder declaration() {
return MethodDeclaration.method(returnType, name, parameters);
}
};
} catch (IllegalArgumentException | NullPointerException e) {
throw new IllegalArgumentException("Invalid signature for " + name + ": " + e.getMessage(), e);
}
}
public static ConstructorBuilder constructor(Parameter... parameters) {
try {
return new ConstructorBuilder(parameters);
} catch (IllegalArgumentException | NullPointerException e) {
throw new IllegalArgumentException("Invalid constructor signature: " + e.getMessage(), e);
}
}
public static class ConstructorBuilder extends Builder {
ConstructorBuilder(Parameter[] parameters) {
super(parameters);
}
public Builder invokeSuper() {
return expression(
ExpressionTemplate.invokeSuperConstructor(new ExpressionTemplate[] {}, TypeReference.NO_TYPES));
}
public Builder invokeSuper(ExpressionTemplate[] parameters, Class>[] parameterTypes) {
TypeReference[] references = new TypeReference[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
references[i] = typeReference(parameterTypes[i]);
}
return invokeSuper(parameters, references);
}
public Builder invokeSuper(ExpressionTemplate[] parameters, TypeReference[] parameterTypes) {
return expression(ExpressionTemplate.invokeSuperConstructor(parameters, parameterTypes));
}
@Override
public MethodTemplate build() {
return buildConstructor(this);
}
@Override
MethodDeclaration.Builder declaration() {
return MethodDeclaration.constructor(parameters);
}
}
public abstract static class Builder {
final Parameter[] parameters;
private final Map locals = new HashMap<>();
private final List statements = new ArrayList<>();
private int modifiers = Modifier.PUBLIC;
Builder(Parameter[] parameters) {
if (parameters == null || parameters.length == 0) {
this.parameters = NO_PARAMETERS;
} else {
this.parameters = Arrays.copyOf(parameters, parameters.length);
}
for (int i = 0; i < this.parameters.length; i++) {
Parameter parameter = requireNonNull(this.parameters[i], "Parameter " + i);
if (null != locals.put(parameter.name(), parameter.type())) {
throw new IllegalArgumentException("Duplicate parameters named \"" + parameter.name() + "\".");
}
}
}
public abstract MethodTemplate build();
public Builder expression(ExpressionTemplate expression) {
statements.add(Statement.expression(expression));
return this;
}
public Builder put(
ExpressionTemplate target, Class> fieldType, String fieldName, ExpressionTemplate expression) {
return put(target, typeReference(fieldType), fieldName, expression);
}
public Builder put(
ExpressionTemplate target, TypeReference fieldType, String fieldName, ExpressionTemplate expression) {
statements.add(Statement.put(target, Lookup.field(fieldType, fieldName), expression));
return this;
}
public Builder modifiers(int modifiers) {
this.modifiers = modifiers;
return this;
}
public Builder returns(ExpressionTemplate value) {
statements.add(Statement.returns(value));
return this;
}
abstract MethodDeclaration.Builder declaration();
}
public TypeReference returnType() {
return returnType;
}
public String name() {
return name;
}
public int modifiers() {
return modifiers;
}
public TypeReference[] parameterTypes() {
if (parameters.length == 0) {
return NO_TYPES;
}
TypeReference[] result = new TypeReference[parameters.length];
for (int i = 0; i < result.length; i++) {
result[i] = parameters[i].type();
}
return result;
}
MethodDeclaration declaration(ClassHandle handle) {
return declaration.build(handle);
}
void generate(CodeBlock generator) {
for (Statement statement : statements) {
statement.generate(generator);
}
}
private static MethodTemplate buildMethod(Builder builder, TypeReference returnType, String name) {
return new MethodTemplate(builder, returnType, name);
}
private static MethodTemplate buildConstructor(Builder builder) {
return new MethodTemplate(builder, TypeReference.VOID, "");
}
private final MethodDeclaration.Builder declaration;
private final Parameter[] parameters;
private final Statement[] statements;
private final TypeReference returnType;
private final String name;
private final int modifiers;
private MethodTemplate(Builder builder, TypeReference returnType, String name) {
this.returnType = returnType;
this.name = name;
this.declaration = builder.declaration();
this.parameters = builder.parameters;
this.statements = builder.statements.toArray(new Statement[0]);
this.modifiers = builder.modifiers;
}
}