net.zerobuilder.compiler.generate.ZeroUtil 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.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeVariableName;
import net.zerobuilder.Access;
import javax.lang.model.element.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
import static com.squareup.javapoet.MethodSpec.constructorBuilder;
import static java.lang.Character.isUpperCase;
import static java.util.Arrays.copyOf;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;
import static java.util.Collections.singletonList;
import static java.util.Collections.unmodifiableList;
import static java.util.stream.Collectors.toList;
public final class ZeroUtil {
static final class ClassNames {
static final ClassName THREAD_LOCAL = ClassName.get(ThreadLocal.class);
private ClassNames() {
throw new UnsupportedOperationException("no instances");
}
}
private static final Set reservedWords = new HashSet<>(Arrays.asList(
"abstract", "continue", "for", "new", "switch", "assert", "default", "if", "package",
"synchronized", "boolean", "do", "goto", "private", "this", "break", "double", "implements",
"protected", "throw", "byte", "else", "import", "public", "throws", "case", "enum",
"instanceof", "return", "transient", "catch", "extends", "int", "short", "try", "char", "final",
"interface", "static", "void", "class", "finally", "long", "strictfp", "volatile", "const",
"float", "native", "super", "while"));
public static final CodeBlock emptyCodeBlock = CodeBlock.of("");
public static String upcase(String s) {
if (s.isEmpty() || Character.isUpperCase(s.charAt(0))) {
return s;
}
return Character.toUpperCase(s.charAt(0)) + s.substring(1);
}
public static String downcase(String s) {
if (s.length() >= 2 && isUpperCase(s.charAt(1))) {
return s;
}
String lowered = Character.toLowerCase(s.charAt(0)) + s.substring(1);
if (reservedWords.contains(lowered)) {
return s;
}
return lowered;
}
public static CodeBlock statement(String format, Object... args) {
return CodeBlock.builder().addStatement(format, args).build();
}
public static ParameterSpec parameterSpec(TypeName type, String name) {
return ParameterSpec.builder(type, name).build();
}
public static FieldSpec fieldSpec(TypeName type, String name, Modifier... modifiers) {
return FieldSpec.builder(type, name, modifiers).build();
}
public static CodeBlock nullCheck(String varName, String message) {
return CodeBlock.builder()
.beginControlFlow("if ($N == null)", varName)
.addStatement("throw new $T($S)", NullPointerException.class, message)
.endControlFlow().build();
}
public static CodeBlock nullCheck(ParameterSpec parameterSpec) {
return nullCheck(parameterSpec.name, parameterSpec.name);
}
public static CodeBlock nullCheck(ParameterSpec parameterSpec, String message) {
return nullCheck(parameterSpec.name, message);
}
static String distinctFrom(String string, String other) {
if (string.equals(other)) {
return 'a' + upcase(string);
}
return string;
}
public static ClassName rawClassName(TypeName typeName) {
if (typeName instanceof ClassName) {
return (ClassName) typeName;
}
if (typeName instanceof ParameterizedTypeName) {
return ((ParameterizedTypeName) typeName).rawType;
}
throw new IllegalArgumentException("not a declared type: " + typeName);
}
private static List typeArguments(TypeName typeName) {
if (typeName instanceof ParameterizedTypeName) {
return ((ParameterizedTypeName) typeName).typeArguments;
}
return emptyList();
}
/**
* @param typeName type
* @return first type argument, if any
* @throws IllegalArgumentException if type has multiple type arguments
*/
static Optional onlyTypeArgument(TypeName typeName) {
List types = typeArguments(typeName);
switch (types.size()) {
case 0:
return Optional.empty();
case 1:
return Optional.of(types.get(0));
default:
throw new IllegalArgumentException("multiple type arguments");
}
}
public static List transform(Collection extends X> input, Function function) {
return input.stream().map(function).collect(toList());
}
public static List
presentInstances(Optional
optional) {
if (optional.isPresent()) {
return singletonList(optional.get());
}
return emptyList();
}
public static
List
concat(P first, List extends P> list) {
List
builder = new ArrayList<>(list.size() + 1);
builder.add(first);
builder.addAll(list);
return builder;
}
public static
List
concat(List extends P> left, List extends P> right) {
if (left.isEmpty()) {
return unmodifiableList(right);
}
if (right.isEmpty()) {
return unmodifiableList(left);
}
List
builder = new ArrayList<>(left.size() + right.size());
builder.addAll(left);
builder.addAll(right);
return builder;
}
public static final Collector, CodeBlock> joinCodeBlocks
= joinCodeBlocks("");
public static Collector, CodeBlock> joinCodeBlocks(String delimiter) {
return new Collector, CodeBlock>() {
@Override
public Supplier> supplier() {
return ArrayList::new;
}
@Override
public BiConsumer, CodeBlock> accumulator() {
return List::add;
}
@Override
public BinaryOperator> combiner() {
return (left, right) -> {
left.addAll(right);
return left;
};
}
@Override
public Function, CodeBlock> finisher() {
return blocks -> {
if (blocks.isEmpty()) {
return emptyCodeBlock;
}
CodeBlock.Builder builder = CodeBlock.builder();
for (int i = 0; i < blocks.size() - 1; i++) {
builder.add(blocks.get(i));
if (!delimiter.isEmpty()) {
builder.add(delimiter);
}
}
builder.add(blocks.get(blocks.size() - 1));
return builder.build();
};
}
@Override
public Set characteristics() {
return emptySet();
}
};
}
public static Collector, List, List> flatList() {
return new Collector, List, List>() {
@Override
public Supplier> supplier() {
return ArrayList::new;
}
@Override
public BiConsumer, List> accumulator() {
return List::addAll;
}
@Override
public BinaryOperator> combiner() {
return (left, right) -> {
left.addAll(right);
return left;
};
}
@Override
public Function, List> finisher() {
return Function.identity();
}
@Override
public Set characteristics() {
return emptySet();
}
};
}
static Collector, R> listCollector(Function, R> finisher) {
return new Collector, R>() {
@Override
public Supplier> supplier() {
return ArrayList::new;
}
@Override
public BiConsumer, E> accumulator() {
return List::add;
}
@Override
public BinaryOperator> combiner() {
return (left, right) -> {
left.addAll(right);
return left;
};
}
@Override
public Function, R> finisher() {
return finisher;
}
@Override
public Set characteristics() {
return emptySet();
}
};
}
static Supplier memoize(Supplier supplier) {
List ref = new ArrayList<>(singletonList(null));
return () -> {
R element = ref.get(0);
if (element == null) {
element = supplier.get();
ref.set(0, element);
}
return element;
};
}
public static MethodSpec constructor(Modifier... modifiers) {
return constructorBuilder().addModifiers(modifiers).build();
}
public static String simpleName(TypeName type) {
if (type.isPrimitive() || type == TypeName.VOID) {
return ((ClassName) type.box()).simpleName();
}
if (type instanceof ClassName) {
return ((ClassName) type).simpleName();
}
if (type instanceof ParameterizedTypeName) {
return ((ParameterizedTypeName) type).rawType.simpleName();
}
throw new IllegalArgumentException("unknown kind: " + type);
}
static int[] createRanking(E[] a, E[] b) {
if (a.length != b.length) {
throw new IllegalArgumentException("a.length != b.length");
}
int[] pos = new int[a.length];
for (int i = 0; i < a.length; i++) {
if (b[i].equals(a[i])) {
pos[i] = i;
} else {
pos[i] = indexOf(b, a[i]);
}
}
return pos;
}
private static int indexOf(E[] b, E el) {
for (int i = 0; i < b.length; i++) {
if (b[i].equals(el)) {
return i;
}
}
throw new IllegalArgumentException("not found: " + el);
}
static List applyRanking(int[] ranking, List input) {
if (input.size() != ranking.length) {
throw new IllegalArgumentException("input.size() != ranking.length");
}
List result = new ArrayList<>(input.size());
for (int i = 0; i < input.size(); i++)
result.add(null);
for (int i = 0; i < input.size(); i++)
result.set(ranking[i], input.get(i));
return result;
}
public static TypeName parameterizedTypeName(ClassName raw, List typeVars) {
if (typeVars.isEmpty()) {
return raw;
}
return ParameterizedTypeName.get(raw, typeVars.toArray(new TypeVariableName[typeVars.size()]));
}
private static Modifier[] addModifier(Modifier modifier, Modifier[] modifiers) {
for (Modifier m : modifiers) {
if (m == modifier) {
return modifiers;
}
}
Modifier[] copy = copyOf(modifiers, modifiers.length + 1);
copy[modifiers.length] = modifier;
return copy;
}
public static Modifier[] modifiers(Access access, Modifier modifiers) {
return access == Access.PUBLIC ?
addModifier(Modifier.PUBLIC, new Modifier[]{modifiers}) :
access == Access.PRIVATE ?
addModifier(Modifier.PRIVATE, new Modifier[]{modifiers}) :
new Modifier[]{modifiers};
}
public static Modifier[] modifiers(Access access) {
return access == Access.PUBLIC ?
new Modifier[]{Modifier.PUBLIC} :
access == Access.PRIVATE ?
new Modifier[]{Modifier.PRIVATE} :
new Modifier[0];
}
private ZeroUtil() {
throw new UnsupportedOperationException("no instances");
}
}