/*
* Copyright (C) 2013 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.ioc.rebind.ioc.bootstrapper;
import org.jboss.errai.codegen.AnnotationEncoder;
import org.jboss.errai.codegen.Context;
import org.jboss.errai.codegen.InterningCallback;
import org.jboss.errai.codegen.Modifier;
import org.jboss.errai.codegen.Statement;
import org.jboss.errai.codegen.builder.ClassStructureBuilder;
import org.jboss.errai.codegen.literal.ArrayLiteral;
import org.jboss.errai.codegen.literal.LiteralFactory;
import org.jboss.errai.codegen.literal.LiteralValue;
import org.jboss.errai.codegen.meta.MetaClass;
import org.jboss.errai.codegen.meta.MetaClassFactory;
import org.jboss.errai.codegen.util.PrivateAccessUtil;
import org.jboss.errai.codegen.util.Refs;
import org.jboss.errai.codegen.util.Stmt;
import org.jboss.errai.ioc.client.QualifierUtil;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Default;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* The interning callback for handling the interning of qualifier annotations and arrays of qualifier annotations.
*
* @author Mike Brock
*/
public class BootstrapInterningCallback implements InterningCallback {
private final Map<Set<Annotation>, String> cachedArrays = new HashMap<Set<Annotation>, String>();
private final MetaClass Annotation_MC = MetaClassFactory.get(Annotation.class);
private final ClassStructureBuilder<?> classStructureBuilder;
private final Context buildContext;
public BootstrapInterningCallback(final ClassStructureBuilder<?> classStructureBuilder,
final Context buildContext) {
this.classStructureBuilder = classStructureBuilder;
this.buildContext = buildContext;
}
@Override
public Statement intern(final LiteralValue<?> literalValue) {
if (literalValue.getValue() == null) {
return null;
}
if (literalValue.getValue() instanceof Annotation) {
final Annotation annotation = (Annotation) literalValue.getValue();
if (annotation.annotationType().equals(Default.class)) {
return Stmt.loadStatic(QualifierUtil.class, "DEFAULT_ANNOTATION");
}
else if (annotation.annotationType().equals(Any.class)) {
return Stmt.loadStatic(QualifierUtil.class, "ANY_ANNOTATION");
}
final Class<? extends Annotation> aClass = annotation.annotationType();
final String fieldName = PrivateAccessUtil.condensify(aClass.getPackage().getName()) + "_" +
aClass.getSimpleName() + "_" + String.valueOf(literalValue.getValue().hashCode()).replaceFirst("\\-", "_");
classStructureBuilder.privateField(fieldName, annotation.annotationType())
.modifiers(Modifier.Final).initializesWith(AnnotationEncoder.encode(annotation))
.finish();
return Refs.get(fieldName);
}
else if (literalValue.getType().isArray()
&& Annotation_MC.isAssignableFrom(literalValue.getType().getOuterComponentType())) {
final Set<Annotation> annotationSet
= new HashSet<Annotation>(Arrays.asList((Annotation[]) literalValue.getValue()));
if (QualifierUtil.isDefaultAnnotations(annotationSet)) {
return Stmt.loadStatic(QualifierUtil.class, "DEFAULT_QUALIFIERS");
}
if (cachedArrays.containsKey(annotationSet)) {
return Refs.get(cachedArrays.get(annotationSet));
}
final MetaClass type = literalValue.getType().getOuterComponentType();
final String fieldName = "arrayOf" + PrivateAccessUtil.condensify(type.getPackageName()) +
type.getName().replaceAll("\\.", "_") + "_"
+ String.valueOf(literalValue.getValue().hashCode()).replaceAll("\\-", "_");
// force rendering of literals in this array first.
for (final Annotation a : annotationSet) {
LiteralFactory.getLiteral(a).generate(buildContext);
}
classStructureBuilder.privateField(fieldName, literalValue.getType())
.modifiers(Modifier.Final).initializesWith(new Statement() {
@Override
public String generate(final Context context) {
return new ArrayLiteral(literalValue.getValue()).getCanonicalString(context);
}
@Override
public MetaClass getType() {
return literalValue.getType();
}
}).finish();
cachedArrays.put(annotationSet, fieldName);
return Refs.get(fieldName);
}
return null;
}
}