blob: 4c97c872cd80aa08dc3a642b15207e82dfd2597c [file] [log] [blame]
// Copyright 2011, 2012 The Apache Software Foundation
//
// 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.apache.tapestry5.internal.plastic;
import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
import org.apache.tapestry5.internal.plastic.asm.Opcodes;
import org.apache.tapestry5.internal.plastic.asm.Type;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings(
{ "rawtypes", "unchecked" })
public abstract class AbstractAnnotationBuilder extends AnnotationVisitor
{
protected final PlasticClassPool pool;
public AbstractAnnotationBuilder(PlasticClassPool pool)
{
super(Opcodes.ASM4);
this.pool = pool;
}
protected abstract void store(String name, Object value);
protected Class elementTypeForArrayAttribute(String name)
{
throw new IllegalStateException("elementTypeForArrayAttribute() may not be invoked here.");
}
@Override
public void visit(String name, Object value)
{
if (value instanceof Type)
{
Type type = (Type) value;
Class valueType = pool.loadClass(type.getClassName());
store(name, valueType);
return;
}
store(name, value);
}
@Override
public void visitEnum(String name, String desc, String value)
{
try
{
String enumClassName = PlasticInternalUtils.objectDescriptorToClassName(desc);
Class enumClass = pool.loader.loadClass(enumClassName);
Object enumValue = Enum.valueOf(enumClass, value);
store(name, enumValue);
}
catch (Exception ex)
{
throw new IllegalArgumentException(String.format("Unable to convert enum annotation attribute %s %s: %s",
value, desc, PlasticInternalUtils.toMessage(ex)), ex);
}
}
@Override
public AnnotationVisitor visitAnnotation(final String name, String desc)
{
final AbstractAnnotationBuilder outerBuilder = this;
final Class nestedAnnotationType = pool.loadClass(PlasticInternalUtils.objectDescriptorToClassName(desc));
// Return a nested builder that constructs the inner annotation and, at the end of
// construction, pushes the final Annotation object into this builder's attributes.
return new AnnotationBuilder(nestedAnnotationType, pool)
{
@Override
public void visitEnd()
{
outerBuilder.store(name, createAnnotation());
};
};
}
@Override
public AnnotationVisitor visitArray(final String name)
{
final List<Object> values = new ArrayList<Object>();
final Class componentType = elementTypeForArrayAttribute(name);
final AbstractAnnotationBuilder outerBuilder = this;
return new AbstractAnnotationBuilder(pool)
{
@Override
protected void store(String name, Object value)
{
values.add(value);
}
@Override
public void visitEnd()
{
Object array = Array.newInstance(componentType, values.size());
// Now, empty arrays may be primitive types and will not cast to Object[], but
// non empty arrays indicate that it was a Class/Enum/Annotation, which can cast
// to Object[]
if (values.size() != 0)
{
for (int i = 0; i<values.size(); i++)
{
Array.set(array, i, values.get(i));
}
}
outerBuilder.store(name, array);
}
};
}
@Override
public void visitEnd()
{
// Nothing to do here. Subclasses use this as a chance to store a value into an outer
// builder.
}
}