/* * Copyright (C) 2011 Red Hat, Inc. and/or its affiliates. * * 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 org.jboss.errai.codegen.builder.impl; import org.jboss.errai.codegen.Context; import org.jboss.errai.codegen.Statement; import org.jboss.errai.codegen.builder.ArrayBuilder; import org.jboss.errai.codegen.builder.ArrayInitializationBuilder; import org.jboss.errai.codegen.builder.callstack.LoadClassReference; import org.jboss.errai.codegen.meta.MetaClass; import org.jboss.errai.codegen.meta.MetaClassFactory; import org.jboss.errai.codegen.util.GenUtil; import java.lang.reflect.Array; /** * StatementBuilder to create and initialize Arrays. * * @author Christian Sadilek <csadilek@redhat.com> * @author Mike Brock */ public class ArrayBuilderImpl extends AbstractStatementBuilder implements ArrayBuilder, ArrayInitializationBuilder { private MetaClass type; private MetaClass componentType; private Object[] dimensions; private Object values = null; protected ArrayBuilderImpl(Context context, CallElementBuilder callElementBuilder) { super(context, callElementBuilder); } @Override public ArrayInitializationBuilder newArray(MetaClass componentType, Object... dimensions) { this.type = componentType.asArrayOf(dimensions.length == 0 ? 1 : dimensions.length); this.componentType = componentType; this.dimensions = dimensions; return this; } @Override public ArrayInitializationBuilder newArray(Class<?> componentType, Object... dimensions) { return newArray(MetaClassFactory.get(componentType), dimensions); } @Override public AbstractStatementBuilder initialize(Object... values) { if (values.length == 1 && values[0].getClass().isArray() && values.getClass().getComponentType().equals(Object.class)) { // this is a workaround for the jdt compiler which is coercing a multi-dimensional array // into the first element of our vararg instead of flattening it out (like javac does). this.values = values[0]; } else { this.values = values; } return this; } @Override public MetaClass getType() { return type; } @Override public String generate(Context context) { if (generatorCache != null) return generatorCache; StringBuilder buf = new StringBuilder(128); buf.append("new ").append(LoadClassReference.getClassReference(componentType, context)); if (values != null) { generateWithInitialization(context, buf); } else { int i = 0; for (Object dimension : dimensions) { try { if (dimension == null) { if (i == 0) { i--; break; } else { buf.append("[]"); } } else { buf.append("[").append(GenUtil.generate(context, dimension).generate(context)).append("]"); } } finally { i++; } } if (i == 0) { throw new RuntimeException("Must provide either dimension expressions or an array initializer"); } } return generatorCache = buf.toString(); } private void generateWithInitialization(Context context, StringBuilder buf) { int dim = 0; Class<?> type = values.getClass(); while (type.isArray()) { dim++; type = type.getComponentType(); } for (int i = 0; i < dim; i++) { buf.append("[]"); } buf.append(" "); generateInitialization(context, buf, values); } private void generateInitialization(Context context, StringBuilder buf, Object values) { buf.append("{ "); int length = Array.getLength(values); for (int i = 0; i < length; i++) { Object element = Array.get(values, i); if (element.getClass().isArray()) { generateInitialization(context, buf, element); } else { Statement statement = GenUtil.generate(context, element); String statementExpr = statement.generate(context); GenUtil.assertAssignableTypes(context, statement.getType(), componentType); buf.append(statementExpr); } if (i + 1 < length) { buf.append(", "); } } buf.append(" }"); } }