/**
* Copyright (c) 2009 Farata Systems http://www.faratasystems.com
*
* Licensed under The MIT License
* Re-distributions of files must retain the above copyright notice.
*
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*
*/
package com.farata.dto2extjs.asap.reflect;
import java.util.Collection;
import java.util.Set;
import java.util.HashSet;
import com.farata.dto2extjs.annotations.JSClass;
import com.farata.dto2extjs.annotations.JSIgnore;
import com.farata.dto2extjs.asap.types.JSTypeReflector;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.apt.Messager;
import com.sun.mirror.declaration.ClassDeclaration;
import com.sun.mirror.declaration.TypeDeclaration;
import com.sun.mirror.type.DeclaredType;
import com.sun.mirror.type.MirroredTypeException;
import com.sun.mirror.type.MirroredTypesException;
import com.sun.mirror.util.SourcePosition;
public class JSSuperclasses {
final private TypeDeclaration _selfClass;
final private Set<DeclaredType> _allSuperclasses;
final private Set<TypeDeclaration> _ignoredSuperclasses;
private int _ignoreAnyCount = 0;
public JSSuperclasses(final TypeDeclaration selfClass, final AnnotationProcessorEnvironment apt) {
_selfClass = selfClass;
_allSuperclasses = new HashSet<DeclaredType>( selfClass.getSuperinterfaces() );
/*
_inheritance = new LinkedHashSet<DeclaredType>();
collectInherited(selfClass, _inheritance, new HashSet<DeclaredType>());
*/
if (selfClass instanceof ClassDeclaration) {
final ClassDeclaration cdecl = (ClassDeclaration)selfClass;
_allSuperclasses.add( cdecl.getSuperclass() );
}
final JSClass jsClass = selfClass.getAnnotation(JSClass.class);
final Set<TypeDeclaration> ignoredSuperclasses = new HashSet<TypeDeclaration>();
if (null != jsClass) {
try {
Object superclasses = jsClass.ignoreSuperclasses();
Class<?>[] ignoredSuperclassArray = superclasses instanceof Class ?
new Class[]{(Class<?>)superclasses} : (Class[])superclasses;
if (null == ignoredSuperclassArray || ignoredSuperclassArray.length == 0) {
}
else {
for (final Class<?> cls : ignoredSuperclassArray) {
if ( cls == JSIgnore.any.class ) {
_ignoreAnyCount++;
} else
ignoredSuperclasses.add( apt.getTypeDeclaration(cls.getName()) );
}
}
} catch (final MirroredTypeException ex) {
final String ignoreAnyClassName = JSIgnore.any.class.getName().replace('$', '.');
if ( ignoreAnyClassName.equals(ex.getQualifiedName()) ) {
_ignoreAnyCount++;
} else
ignoredSuperclasses.add( apt.getTypeDeclaration(ex.getQualifiedName()) );
} catch (final MirroredTypesException ex) {
Collection<String> ignoredSuperclassArray = ex.getQualifiedNames();
if (null == ignoredSuperclassArray || ignoredSuperclassArray.size() == 0) {
}
else {
final String ignoreAnyClassName = JSIgnore.any.class.getName().replace('$', '.');
for (final String className : ignoredSuperclassArray) {
if ( ignoreAnyClassName.equals(className) ) {
_ignoreAnyCount++;
} else
ignoredSuperclasses.add( apt.getTypeDeclaration(className) );
}
}
}
}
_ignoredSuperclasses = ignoredSuperclasses;
}
// Inheritance processing is not necessary
/*
final private Set<DeclaredType> _inheritance;
public Collection<DeclaredType> inheritance() {
return _inheritance;
}
static void collectInherited(final TypeDeclaration current, final Set<DeclaredType> types, final Set<DeclaredType> visitedInterfaces) {
if (current instanceof ClassDeclaration) {
final ClassDeclaration cdecl = ClassDeclaration.class.cast(current);
final ClassType ctype = cdecl.getSuperclass();
if (null != ctype) {
types.add(ctype);
collectInherited(ctype.getDeclaration(), types, visitedInterfaces);
}
}
for (final InterfaceType itype : current.getSuperinterfaces()) {
if (visitedInterfaces.contains(itype))
continue;
types.add(itype);
collectInherited(itype.getDeclaration(), types, visitedInterfaces);
}
}
*/
public boolean validate(final AnnotationProcessorEnvironment apt) {
boolean valid = true;
final Messager messager = apt.getMessager();
final SourcePosition ignoreSuperclassesPosition = ignoreSuperclassesPosition();
if (_ignoreAnyCount > 1) {
valid = false;
messager.printError(
ignoreSuperclassesPosition,
"<IGNORE_ANY_CLASS> tag may be defined only once"
);
}
if (_ignoreAnyCount >= 1 && _ignoredSuperclasses.size() > 0) {
valid = false;
messager.printError(
ignoreSuperclassesPosition,
"<IGNORE_ANY_CLASS> may not be combined with explicit class list"
);
}
final Set<TypeDeclaration> ignoredSuperclasses = new HashSet<TypeDeclaration>(_ignoredSuperclasses);
for (final DeclaredType type : _allSuperclasses) {
final TypeDeclaration declaration = type.getDeclaration();
final boolean wasIgnored = ignoredSuperclasses.remove( declaration );
if (wasIgnored && null != declaration.getAnnotation(JSClass.class)) {
messager.printError(
ignoreSuperclassesPosition,
declaration.getQualifiedName() + " may not be excluded, it is annotated as @JSClass"
);
}
}
for (final TypeDeclaration declaration : ignoredSuperclasses) {
messager.printWarning(
ignoreSuperclassesPosition,
"Class \"" + declaration.getQualifiedName() + "\" is not used as interface/superclass"
);
}
return valid;
}
private SourcePosition ignoreSuperclassesPosition() {
return JSTypeReflector.getJSClassAnnotationAttributePosition(_selfClass, "ignoreSuperclasses");
}
public boolean ignored(final TypeDeclaration declaration) {
final JSClass jsClass = declaration.getAnnotation(JSClass.class);
return (null == jsClass && _ignoreAnyCount > 0) || _ignoredSuperclasses.contains( declaration );
}
public boolean superInterfaceIgnored(final TypeDeclaration declaration) {
if ( ignored(declaration) )
return true;
final String qname = declaration.getQualifiedName();
return qname.startsWith("java.") || qname.startsWith("javax.");
}
public boolean superClassIgnored(final TypeDeclaration declaration) {
if ( ignored(declaration) )
return true;
final String qname = declaration.getQualifiedName();
return qname.equals("java.lang.Object");
}
}