/** * Copyright 2011-2017 Asakusa Framework Team. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.asakusafw.utils.java.model.util; import java.io.PrintWriter; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import com.asakusafw.utils.java.internal.model.syntax.ModelFactoryImpl; import com.asakusafw.utils.java.internal.model.util.LiteralAnalyzer; import com.asakusafw.utils.java.internal.model.util.ModelEmitter; import com.asakusafw.utils.java.internal.model.util.ReflectionTypeMapper; import com.asakusafw.utils.java.model.syntax.ArrayInitializer; import com.asakusafw.utils.java.model.syntax.BasicTypeKind; import com.asakusafw.utils.java.model.syntax.ClassLiteral; import com.asakusafw.utils.java.model.syntax.Expression; import com.asakusafw.utils.java.model.syntax.Literal; import com.asakusafw.utils.java.model.syntax.Model; import com.asakusafw.utils.java.model.syntax.ModelFactory; import com.asakusafw.utils.java.model.syntax.ModelKind; import com.asakusafw.utils.java.model.syntax.Name; import com.asakusafw.utils.java.model.syntax.QualifiedName; import com.asakusafw.utils.java.model.syntax.SimpleName; import com.asakusafw.utils.java.model.syntax.Type; /** * Utilities for {@link Model}. */ public final class Models { private static final Map<Class<?>, BasicTypeKind> WRAPPER_TYPE_KINDS; static { Map<Class<?>, BasicTypeKind> map = new HashMap<>(); map.put(Byte.class, BasicTypeKind.BYTE); map.put(Short.class, BasicTypeKind.SHORT); map.put(Integer.class, BasicTypeKind.INT); map.put(Long.class, BasicTypeKind.LONG); map.put(Float.class, BasicTypeKind.FLOAT); map.put(Double.class, BasicTypeKind.DOUBLE); map.put(Character.class, BasicTypeKind.CHAR); map.put(Boolean.class, BasicTypeKind.BOOLEAN); WRAPPER_TYPE_KINDS = map; } /** * Returns a basic Java DOM factory. * @return a Java DOM factory */ public static ModelFactory getModelFactory() { return new ModelFactoryImpl(); } /** * Returns a simple name list of the target name. * @param name the target name * @return the simple name list * @throws IllegalArgumentException if the parameter is {@code null} */ public static List<SimpleName> toList(Name name) { if (name == null) { throw new IllegalArgumentException("name must not be null"); //$NON-NLS-1$ } ModelKind kind = name.getModelKind(); if (kind == ModelKind.SIMPLE_NAME) { return Collections.singletonList((SimpleName) name); } else { LinkedList<SimpleName> result = new LinkedList<>(); Name current = name; do { QualifiedName qname = (QualifiedName) current; result.addFirst(qname.getSimpleName()); current = qname.getQualifier(); } while (current.getModelKind() == ModelKind.QUALIFIED_NAME); assert current.getModelKind() == ModelKind.SIMPLE_NAME; result.addFirst((SimpleName) current); return result; } } /** * Returns a new name which is concatenated the prefix name with the suffix name string. * @param factory the Java DOM factory * @param prefix the prefix name * @param rest the suffix name string (may be a qualified name string) * @return the concatenated name * @throws IllegalArgumentException if the parameters are {@code null} */ public static Name append(ModelFactory factory, Name prefix, String rest) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } if (prefix == null) { throw new IllegalArgumentException("prefix must not be null"); //$NON-NLS-1$ } if (rest == null) { throw new IllegalArgumentException("rest must not be null"); //$NON-NLS-1$ } Name name = Models.toName(factory, rest); return append(factory, prefix, name); } /** * Concatenates each name and returns it. * @param factory the Java DOM factory * @param names the names to be concatenated * @return the concatenated name * @throws IllegalArgumentException if the names are empty, or the parameters are {@code null} */ public static Name append(ModelFactory factory, Name... names) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } if (names == null) { throw new IllegalArgumentException("names must not be null"); //$NON-NLS-1$ } if (names.length == 0) { throw new IllegalArgumentException("names must have elements"); //$NON-NLS-1$ } if (names.length == 1) { return names[0]; } Name current = names[0]; for (int i = 1; i < names.length; i++) { for (SimpleName segment : toList(names[i])) { current = factory.newQualifiedName(current, segment); } } return current; } /** * Emits Java DOM object into the target writer. * If there are elements which have {@link CommentEmitTrait}, * their comments will be also emitted into the writer. * @param model the target DOM object * @param writer the target writer * @throws IllegalArgumentException if the parameters are {@code null} */ public static void emit(Model model, PrintWriter writer) { if (model == null) { throw new IllegalArgumentException("model must not be null"); //$NON-NLS-1$ } if (writer == null) { throw new IllegalArgumentException("writer must not be null"); //$NON-NLS-1$ } ModelEmitter emitter = new ModelEmitter(writer); emitter.emit(model); } /** * Returns a Java DOM object from the Java reflective object. * @param factory the Java DOM factory * @param type the target reflective object * @return the corresponded Java DOM object * @throws IllegalArgumentException if the parameters are {@code null} */ public static Type toType(ModelFactory factory, java.lang.reflect.Type type) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } if (type == null) { throw new IllegalArgumentException("type must not be null"); //$NON-NLS-1$ } return new ReflectionTypeMapper().dispatch(type, factory); } /** * Returns a name from the name string. * @param factory the Java DOM factory * @param nameString the target name string * @return the corresponded name * @throws IllegalArgumentException if the parameters are {@code null} */ public static Name toName(ModelFactory factory, String nameString) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } if (nameString == null) { throw new IllegalArgumentException("nameString must not be null"); //$NON-NLS-1$ } String[] segments = nameString.trim().split("\\s*\\.\\s*"); //$NON-NLS-1$ if (segments.length == 0 || segments[0].length() == 0) { throw new IllegalArgumentException("nameString is empty"); //$NON-NLS-1$ } Name left = factory.newSimpleName(segments[0]); for (int i = 1; i < segments.length; i++) { SimpleName right = factory.newSimpleName(segments[i]); left = factory.newQualifiedName(left, right); } return left; } /** * Returns the fully qualified name of the target enum constant. * @param factory the Java DOM factory * @param constant the target enum constant * @return the corresponded name * @throws IllegalArgumentException if the parameters are {@code null} */ public static Name toName(ModelFactory factory, Enum<?> constant) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } if (constant == null) { throw new IllegalArgumentException("constant must not be null"); //$NON-NLS-1$ } Name typeName = toName(factory, constant.getDeclaringClass().getName()); return factory.newQualifiedName(typeName, factory.newSimpleName(constant.name())); } /** * Returns a Java literal (with cast operation) of the target value. * @param factory the Java DOM factory * @param value the target value * @return the corresponded Java literal * @throws IllegalArgumentException if the parameters are {@code null} */ public static Expression toLiteral(ModelFactory factory, byte value) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } String token = LiteralAnalyzer.intLiteralOf(value); return factory.newCastExpression(factory.newBasicType(BasicTypeKind.BYTE), factory.newLiteral(token)); } /** * Returns a Java literal (with cast operation) of the target value. * @param factory the Java DOM factory * @param value the target value * @return the corresponded Java literal * @throws IllegalArgumentException if the parameter is {@code null} */ public static Expression toLiteral(ModelFactory factory, short value) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } String token = LiteralAnalyzer.intLiteralOf(value); return factory.newCastExpression(factory.newBasicType(BasicTypeKind.SHORT), factory.newLiteral(token)); } /** * Returns a Java literal of the target value. * @param factory the Java DOM factory * @param value the target value * @return the corresponded Java literal * @throws IllegalArgumentException if the parameter is {@code null} */ public static Literal toLiteral(ModelFactory factory, int value) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } String token = LiteralAnalyzer.intLiteralOf(value); return factory.newLiteral(token); } /** * Returns a Java literal of the target value. * @param factory the Java DOM factory * @param value the target value * @return the corresponded Java literal * @throws IllegalArgumentException if the parameter is {@code null} */ public static Literal toLiteral(ModelFactory factory, long value) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } String token = LiteralAnalyzer.longLiteralOf(value); return factory.newLiteral(token); } /** * Returns a Java literal of the target value. * @param factory the Java DOM factory * @param value the target value * @return the corresponded Java literal * @throws IllegalArgumentException if the parameter is {@code null} */ public static Literal toLiteral(ModelFactory factory, float value) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } String token = LiteralAnalyzer.floatLiteralOf(value); return factory.newLiteral(token); } /** * Returns a Java literal of the target value. * @param factory the Java DOM factory * @param value the target value * @return the corresponded Java literal * @throws IllegalArgumentException if the parameter is {@code null} */ public static Literal toLiteral(ModelFactory factory, double value) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } String token = LiteralAnalyzer.doubleLiteralOf(value); return factory.newLiteral(token); } /** * Returns a Java literal of the target value. * @param factory the Java DOM factory * @param value the target value * @return the corresponded Java literal * @throws IllegalArgumentException if the parameter is {@code null} */ public static Literal toLiteral(ModelFactory factory, boolean value) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } String token = LiteralAnalyzer.booleanLiteralOf(value); return factory.newLiteral(token); } /** * Returns a Java literal of the target value. * @param factory the Java DOM factory * @param value the target value * @return the corresponded Java literal * @throws IllegalArgumentException if the parameter is {@code null} */ public static Literal toLiteral(ModelFactory factory, char value) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } String token = LiteralAnalyzer.charLiteralOf(value); return factory.newLiteral(token); } /** * Returns a Java literal of the target value. * @param factory the Java DOM factory * @param value the target value * @return the corresponded Java literal * @throws IllegalArgumentException if the parameters are {@code null} */ public static Literal toLiteral(ModelFactory factory, String value) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } if (value == null) { throw new IllegalArgumentException("value must not be null"); //$NON-NLS-1$ } String token = LiteralAnalyzer.stringLiteralOf(value); return factory.newLiteral(token); } /** * Returns a Java literal of the target value. * The value must be one of the following value: * <ul> * <li> the primitive wrapper object </li> * <li> {@code java.lang.String} </li> * <li> {@code java.lang.reflect.Type} </li> * <li> {@code null} </li> * </ul> * @param factory the Java DOM factory * @param value the target value * @return the corresponded Java literal * @throws IllegalArgumentException if the value is something wrong, or the parameters are {@code null} */ public static Expression toLiteral(ModelFactory factory, Object value) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } if (value == null) { return toNullLiteral(factory); } Class<? extends Object> valueClass = value.getClass(); BasicTypeKind kind = WRAPPER_TYPE_KINDS.get(valueClass); if (kind != null) { switch (kind) { case BYTE: return toLiteral(factory, (byte) (Byte) value); case SHORT: return toLiteral(factory, (short) (Short) value); case INT: return toLiteral(factory, (int) (Integer) value); case LONG: return toLiteral(factory, (long) (Long) value); case FLOAT: return toLiteral(factory, (float) (Float) value); case DOUBLE: return toLiteral(factory, (double) (Double) value); case CHAR: return toLiteral(factory, (char) (Character) value); case BOOLEAN: return toLiteral(factory, (boolean) (Boolean) value); default: throw new AssertionError(kind); } } else if (valueClass == String.class) { return toLiteral(factory, (String) value); } else if (value instanceof java.lang.reflect.Type) { return toClassLiteral(factory, (java.lang.reflect.Type) value); } throw new IllegalArgumentException(MessageFormat.format( "Cannot convert {0} to literal ({1})", value, valueClass)); } /** * Returns a type literal of the target type. * @param factory the Java DOM factory * @param type the target Java type * @return the corresponded Java literal * @throws IllegalArgumentException if the parameters are {@code null} */ public static ClassLiteral toClassLiteral(ModelFactory factory, java.lang.reflect.Type type) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } if (type == null) { throw new IllegalArgumentException("type must not be null"); //$NON-NLS-1$ } return factory.newClassLiteral(Models.toType(factory, type)); } /** * Returns a {@code null} literal. * @param factory the Java DOM factory * @return the literal * @throws IllegalArgumentException if the parameter is {@code null} */ public static Literal toNullLiteral(ModelFactory factory) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } String token = LiteralAnalyzer.nullLiteral(); return factory.newLiteral(token); } /** * Returns an array initializer which contains the original elements as related Java expression. * @param factory the Java DOM factory * @param array the target array * @return the corresponded array initializer * @throws IllegalArgumentException if the parameters are {@code null} */ public static ArrayInitializer toArrayInitializer(ModelFactory factory, int[] array) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } if (array == null) { throw new IllegalArgumentException("array must not be null"); //$NON-NLS-1$ } List<Expression> literals = new ArrayList<>(); for (int value : array) { literals.add(Models.toLiteral(factory, value)); } return factory.newArrayInitializer(literals); } /** * Returns an array initializer which contains the original elements as related Java expression. * @param factory the Java DOM factory * @param array the target array * @return the corresponded array initializer * @throws IllegalArgumentException if the parameters are {@code null} */ public static ArrayInitializer toArrayInitializer(ModelFactory factory, float[] array) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } if (array == null) { throw new IllegalArgumentException("array must not be null"); //$NON-NLS-1$ } List<Expression> literals = new ArrayList<>(); for (float value : array) { literals.add(Models.toLiteral(factory, value)); } return factory.newArrayInitializer(literals); } /** * Returns an array initializer which contains the original elements as related Java expression. * @param factory the Java DOM factory * @param array the target array * @return the corresponded array initializer * @throws IllegalArgumentException if the parameters are {@code null} */ public static ArrayInitializer toArrayInitializer(ModelFactory factory, long[] array) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } if (array == null) { throw new IllegalArgumentException("array must not be null"); //$NON-NLS-1$ } List<Expression> literals = new ArrayList<>(); for (long value : array) { literals.add(Models.toLiteral(factory, value)); } return factory.newArrayInitializer(literals); } /** * Returns an array initializer which contains the original elements as related Java expression. * @param factory the Java DOM factory * @param array the target array * @return the corresponded array initializer * @throws IllegalArgumentException if the parameters are {@code null} */ public static ArrayInitializer toArrayInitializer(ModelFactory factory, double[] array) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } if (array == null) { throw new IllegalArgumentException("array must not be null"); //$NON-NLS-1$ } List<Expression> literals = new ArrayList<>(); for (double value : array) { literals.add(Models.toLiteral(factory, value)); } return factory.newArrayInitializer(literals); } /** * Returns an array initializer which contains the original elements as related Java expression. * @param factory the Java DOM factory * @param array the target array * @return the corresponded array initializer * @throws IllegalArgumentException if the parameters are {@code null} */ public static ArrayInitializer toArrayInitializer(ModelFactory factory, char[] array) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } if (array == null) { throw new IllegalArgumentException("array must not be null"); //$NON-NLS-1$ } List<Expression> literals = new ArrayList<>(); for (char value : array) { literals.add(Models.toLiteral(factory, value)); } return factory.newArrayInitializer(literals); } /** * Returns an array initializer which contains the original elements as related Java expression. * @param factory the Java DOM factory * @param array the target array * @return the corresponded array initializer * @throws IllegalArgumentException if the parameters are {@code null} */ public static ArrayInitializer toArrayInitializer(ModelFactory factory, boolean[] array) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } if (array == null) { throw new IllegalArgumentException("array must not be null"); //$NON-NLS-1$ } List<Expression> literals = new ArrayList<>(); for (boolean value : array) { literals.add(Models.toLiteral(factory, value)); } return factory.newArrayInitializer(literals); } /** * Returns an array initializer which contains the original elements as related Java expression. * @param factory the Java DOM factory * @param array the target array * @return the corresponded array initializer * @throws IllegalArgumentException if the parameters are {@code null} */ public static ArrayInitializer toArrayInitializer(ModelFactory factory, byte[] array) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } if (array == null) { throw new IllegalArgumentException("array must not be null"); //$NON-NLS-1$ } List<Expression> literals = new ArrayList<>(); for (byte value : array) { literals.add(Models.toLiteral(factory, value)); } return factory.newArrayInitializer(literals); } /** * Returns an array initializer which contains the original elements as related Java expression. * @param factory the Java DOM factory * @param array the target array * @return the corresponded array initializer * @throws IllegalArgumentException if the parameters are {@code null} */ public static ArrayInitializer toArrayInitializer(ModelFactory factory, short[] array) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } if (array == null) { throw new IllegalArgumentException("array must not be null"); //$NON-NLS-1$ } List<Expression> literals = new ArrayList<>(); for (short value : array) { literals.add(Models.toLiteral(factory, value)); } return factory.newArrayInitializer(literals); } /** * Returns an array initializer which contains the original elements as related Java expression. * @param factory the Java DOM factory * @param array the target array * @return the corresponded array initializer * @throws IllegalArgumentException if the parameters are {@code null} */ public static ArrayInitializer toArrayInitializer(ModelFactory factory, String[] array) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } if (array == null) { throw new IllegalArgumentException("array must not be null"); //$NON-NLS-1$ } List<Expression> literals = new ArrayList<>(); for (String value : array) { if (value == null) { literals.add(Models.toNullLiteral(factory)); } else { literals.add(Models.toLiteral(factory, value)); } } return factory.newArrayInitializer(literals); } /** * Returns an array initializer which contains the original elements as related Java expression. * @param factory the Java DOM factory * @param array the target array * @return the corresponded array initializer * @throws IllegalArgumentException if the parameters are {@code null} */ public static ArrayInitializer toArrayInitializer(ModelFactory factory, java.lang.reflect.Type[] array) { if (factory == null) { throw new IllegalArgumentException("factory must not be null"); //$NON-NLS-1$ } if (array == null) { throw new IllegalArgumentException("array must not be null"); //$NON-NLS-1$ } List<Expression> literals = new ArrayList<>(); for (java.lang.reflect.Type value : array) { if (value == null) { literals.add(Models.toNullLiteral(factory)); } else { literals.add(Models.toClassLiteral(factory, value)); } } return factory.newArrayInitializer(literals); } private Models() { throw new AssertionError(); } }