Search in sources :

Example 16 with Clazz

use of aQute.bnd.osgi.Clazz in project bnd by bndtools.

the class ClassParserTest method testStackMapTable.

public void testStackMapTable() throws Exception {
    Clazz c = new Clazz(a, "test/stackmaptable", null);
    c.parseClassFile(getClass().getResourceAsStream("stackmaptable/ClassRefInStackMapTable.class"));
    assertTrue(c.getReferred().contains(a.getPackageRef("javax/crypto/spec")));
    assertTrue(c.getReferred().contains(a.getPackageRef("javax/crypto")));
}
Also used : Clazz(aQute.bnd.osgi.Clazz)

Example 17 with Clazz

use of aQute.bnd.osgi.Clazz in project bnd by bndtools.

the class JavaElement method classElement.

/**
	 * Calculate the class element. This requires parsing the class file and
	 * finding all the methods that were added etc. The parsing will take super
	 * interfaces and super classes into account. For this reason it maintains a
	 * queue of classes/interfaces to parse.
	 * 
	 * @param analyzer
	 * @param clazz
	 * @param infos
	 * @throws Exception
	 */
Element classElement(final Clazz clazz) throws Exception {
    Element e = cache.get(clazz);
    if (e != null)
        return e;
    final Set<Element> members = Create.set();
    final Set<MethodDef> methods = Create.set();
    final Set<Clazz.FieldDef> fields = Create.set();
    final MultiMap<Clazz.Def, Element> annotations = new MultiMap<Clazz.Def, Element>();
    final TypeRef name = clazz.getClassName();
    final String fqn = name.getFQN();
    final String shortName = name.getShortName();
    // Check if this clazz is actually a provider or not
    // providers must be listed in the exported package in the
    // PROVIDER_TYPE directive.
    Instructions matchers = providerMatcher.get(name.getPackageRef());
    boolean p = matchers != null && matchers.matches(shortName);
    final AtomicBoolean provider = new AtomicBoolean(p);
    //
    // Check if we already had this clazz in the cache
    //
    // for super classes
    Element before = cache.get(clazz);
    if (before != null)
        return before;
    clazz.parseClassFileWithCollector(new ClassDataCollector() {

        boolean memberEnd;

        Clazz.FieldDef last;

        @Override
        public void version(int minor, int major) {
            javas.add(Clazz.JAVA.getJava(major, minor));
        }

        @Override
        public void method(MethodDef defined) {
            if ((defined.isProtected() || defined.isPublic())) {
                last = defined;
                methods.add(defined);
            } else {
                last = null;
            }
        }

        @Override
        public void deprecated() {
            if (memberEnd)
                clazz.setDeprecated(true);
            else if (last != null)
                last.setDeprecated(true);
        }

        @Override
        public void field(Clazz.FieldDef defined) {
            if (defined.isProtected() || defined.isPublic()) {
                last = defined;
                fields.add(defined);
            } else
                last = null;
        }

        @Override
        public void constant(Object o) {
            if (last != null) {
                // Must be accessible now
                last.setConstant(o);
            }
        }

        @Override
        public void extendsClass(TypeRef name) throws Exception {
            String comment = null;
            if (!clazz.isInterface())
                comment = inherit(members, name);
            Clazz c = analyzer.findClass(name);
            if ((c == null || c.isPublic()) && !name.isObject())
                members.add(new Element(EXTENDS, name.getFQN(), null, MICRO, MAJOR, comment));
        }

        @Override
        public void implementsInterfaces(TypeRef[] names) throws Exception {
            // ignore type reordering
            Arrays.sort(names);
            for (TypeRef name : names) {
                String comment = null;
                if (clazz.isInterface() || clazz.isAbstract())
                    comment = inherit(members, name);
                members.add(new Element(IMPLEMENTS, name.getFQN(), null, MINOR, MAJOR, comment));
            }
        }

        /**
			 */
        Set<Element> OBJECT = Create.set();

        public String inherit(final Set<Element> members, TypeRef name) throws Exception {
            if (name.isObject()) {
                if (OBJECT.isEmpty()) {
                    Clazz c = analyzer.findClass(name);
                    if (c == null) {
                        // available
                        return null;
                    }
                    Element s = classElement(c);
                    for (Element child : s.children) {
                        if (INHERITED.contains(child.type)) {
                            String n = child.getName();
                            if (child.type == METHOD) {
                                if (n.startsWith("<init>") || "getClass()".equals(child.getName()) || n.startsWith("wait(") || n.startsWith("notify(") || n.startsWith("notifyAll("))
                                    continue;
                            }
                            if (isStatic(child))
                                continue;
                            OBJECT.add(child);
                        }
                    }
                }
                members.addAll(OBJECT);
            } else {
                Clazz c = analyzer.findClass(name);
                if (c == null) {
                    return inherit(members, analyzer.getTypeRef("java/lang/Object"));
                }
                Element s = classElement(c);
                for (Element child : s.children) {
                    if (isStatic(child))
                        continue;
                    if (INHERITED.contains(child.type) && !child.name.startsWith("<")) {
                        members.add(child);
                    }
                }
            }
            return null;
        }

        private boolean isStatic(Element child) {
            boolean isStatic = child.get("static") != null;
            return isStatic;
        }

        /**
			 * Deprecated annotations and Provider/Consumer Type (both bnd and
			 * OSGi) are treated special. Other annotations are turned into a
			 * tree. Starting with ANNOTATED, and then properties. A property is
			 * a PROPERTY property or an ANNOTATED property if it is an
			 * annotation. If it is an array, the key is suffixed with the
			 * index.
			 * 
			 * <pre>
			 *  public @interface Outer { Inner[] value(); }
			 * public @interface Inner { String[] value(); } @Outer(
			 * { @Inner("1","2"}) } class Xyz {} ANNOTATED Outer
			 * (CHANGED/CHANGED) ANNOTATED Inner (CHANGED/CHANGED) PROPERTY
			 * value.0=1 (CHANGED/CHANGED) PROPERTY value.1=2 (CHANGED/CHANGED)
			 * </pre>
			 */
        @Override
        public void annotation(Annotation annotation) {
            if (Deprecated.class.getName().equals(annotation.getName().getFQN())) {
                if (memberEnd)
                    clazz.setDeprecated(true);
                else if (last != null)
                    last.setDeprecated(true);
                return;
            }
            Element e = annotatedToElement(annotation);
            if (memberEnd) {
                members.add(e);
                //
                // Check for the provider/consumer. We use strings because
                // these are not officially
                // released yet
                //
                String name = annotation.getName().getFQN();
                if ("aQute.bnd.annotation.ProviderType".equals(name) || "org.osgi.annotation.versioning.ProviderType".equals(name)) {
                    provider.set(true);
                } else if ("aQute.bnd.annotation.ConsumerType".equals(name) || "org.osgi.annotation.versioning.ConsumerType".equals(name)) {
                    provider.set(false);
                }
            } else if (last != null)
                annotations.add(last, e);
        }

        /*
			 * Return an ANNOTATED element for this annotation. An ANNOTATED
			 * element contains either PROPERTY children or ANNOTATED children.
			 */
        private Element annotatedToElement(Annotation annotation) {
            Collection<Element> properties = Create.set();
            for (String key : annotation.keySet()) {
                addAnnotationMember(properties, key, annotation.get(key));
            }
            return new Element(ANNOTATED, annotation.getName().getFQN(), properties, CHANGED, CHANGED, null);
        }

        /*
			 * This method detects 3 cases: An Annotation, which means it
			 * creates a new child ANNOTATED element, an array, which means it
			 * will repeat recursively but suffixes the key with the index, or a
			 * simple value which is turned into a string.
			 */
        private void addAnnotationMember(Collection<Element> properties, String key, Object member) {
            if (member instanceof Annotation) {
                properties.add(annotatedToElement((Annotation) member));
            } else if (member.getClass().isArray()) {
                int l = Array.getLength(member);
                for (int i = 0; i < l; i++) {
                    addAnnotationMember(properties, key + "." + i, Array.get(member, i));
                }
            } else {
                StringBuilder sb = new StringBuilder();
                sb.append(key);
                sb.append('=');
                if (member instanceof String) {
                    sb.append("'");
                    sb.append(member);
                    sb.append("'");
                } else
                    sb.append(member);
                properties.add(new Element(PROPERTY, sb.toString(), null, CHANGED, CHANGED, null));
            }
        }

        @Override
        public void innerClass(TypeRef innerClass, TypeRef outerClass, String innerName, int innerClassAccessFlags) throws Exception {
            Clazz clazz = analyzer.findClass(innerClass);
            if (clazz != null)
                clazz.setInnerAccess(innerClassAccessFlags);
            if (Modifier.isProtected(innerClassAccessFlags) || Modifier.isPublic(innerClassAccessFlags))
                return;
            notAccessible.add(innerClass);
        }

        @Override
        public void memberEnd() {
            memberEnd = true;
        }
    });
    // This is the heart of the semantic versioning. If we
    // add or remove a method from an interface then
    Delta add;
    Delta remove;
    Type type;
    if (clazz.isInterface())
        if (clazz.isAnnotation())
            type = ANNOTATION;
        else
            type = INTERFACE;
    else if (clazz.isEnum())
        type = ENUM;
    else
        type = CLASS;
    if (type == INTERFACE) {
        if (provider.get()) {
            // Adding a method for a provider is not an issue
            // because it must be aware of the changes
            add = MINOR;
            // Removing a method influences consumers since they
            // tend to call this guy.
            remove = MAJOR;
        } else {
            // Adding a method is a major change
            // because the consumer has to implement it
            // or the provider will call a non existent
            // method on the consumer
            add = MAJOR;
            // Removing a method is not an issue for
            // providers, however, consumers could potentially
            // call through this interface :-(
            remove = MAJOR;
        }
    } else {
        // Adding a method to a class can never do any harm
        // except when the class is extended and the new
        // method clashes with the new method. That is
        // why API classes in general should be final, at
        // least not extended by consumers.
        add = MINOR;
        // Removing it will likely hurt consumers
        remove = MAJOR;
    }
    for (MethodDef m : methods) {
        if (m.isSynthetic()) {
            // Ignore synthetic methods
            continue;
        }
        Collection<Element> children = annotations.get(m);
        if (children == null)
            children = new HashSet<Element>();
        access(children, m.getAccess(), m.isDeprecated(), provider.get());
        // in a final class.
        if (clazz.isFinal())
            children.remove(FINAL);
        children.add(getReturn(m.getType()));
        if (clazz.isInterface() && !m.isAbstract()) {
            //
            // We have a Java 8 default method!
            // Such a method is always a minor update
            //
            add = MINOR;
        }
        String signature = m.getName() + toString(m.getPrototype());
        Element member = new Element(METHOD, signature, children, add, provider.get() && !m.isPublic() ? MINOR : remove, null);
        if (!members.add(member)) {
            members.remove(member);
            members.add(member);
        }
    }
    for (Clazz.FieldDef f : fields) {
        if (f.isSynthetic()) {
            // Ignore synthetic fields
            continue;
        }
        Collection<Element> children = annotations.get(f);
        if (children == null)
            children = new HashSet<Element>();
        // Fields can have a constant value, this is a new element
        if (f.getConstant() != null) {
            children.add(new Element(CONSTANT, f.getConstant().toString(), null, CHANGED, CHANGED, null));
        }
        access(children, f.getAccess(), f.isDeprecated(), provider.get());
        children.add(getReturn(f.getType()));
        Element member = new Element(FIELD, f.getName(), children, MINOR, provider.get() && !f.isPublic() ? MINOR : MAJOR, null);
        if (!members.add(member)) {
            members.remove(member);
            members.add(member);
        }
    }
    access(members, clazz.getAccess(), clazz.isDeprecated(), provider.get());
    // And make the result
    Element s = new Element(type, fqn, members, MINOR, MAJOR, null);
    cache.put(clazz, s);
    return s;
}
Also used : MethodDef(aQute.bnd.osgi.Clazz.MethodDef) TypeRef(aQute.bnd.osgi.Descriptors.TypeRef) MultiMap(aQute.lib.collections.MultiMap) Clazz(aQute.bnd.osgi.Clazz) ClassDataCollector(aQute.bnd.osgi.ClassDataCollector) HashSet(java.util.HashSet) MethodDef(aQute.bnd.osgi.Clazz.MethodDef) Instructions(aQute.bnd.osgi.Instructions) Annotation(aQute.bnd.osgi.Annotation) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Type(aQute.bnd.service.diff.Type) Delta(aQute.bnd.service.diff.Delta) Collection(java.util.Collection)

Example 18 with Clazz

use of aQute.bnd.osgi.Clazz in project bnd by bndtools.

the class DiffPluginImpl method hasSource.

private boolean hasSource(Analyzer analyzer, String path) throws Exception {
    if (!path.endsWith(".class"))
        return false;
    TypeRef type = analyzer.getTypeRefFromPath(path);
    PackageRef packageRef = type.getPackageRef();
    Clazz clazz = analyzer.findClass(type);
    if (clazz == null)
        return false;
    String sourceFile = clazz.getSourceFile();
    if (sourceFile == null)
        return false;
    String source = "OSGI-OPT/src/" + packageRef.getBinary() + "/" + sourceFile;
    Resource sourceResource = analyzer.getJar().getResource(source);
    if (sourceResource == null)
        return false;
    return true;
}
Also used : TypeRef(aQute.bnd.osgi.Descriptors.TypeRef) Resource(aQute.bnd.osgi.Resource) Clazz(aQute.bnd.osgi.Clazz) PackageRef(aQute.bnd.osgi.Descriptors.PackageRef)

Example 19 with Clazz

use of aQute.bnd.osgi.Clazz in project bnd by bndtools.

the class CalltreeResource method writeCalltree.

/**
	 * Print the call tree in XML.
	 * 
	 * @param out The output writer
	 * @param classes The set of classes
	 * @throws Exception Any errors
	 */
public static void writeCalltree(PrintWriter out, Collection<Clazz> classes) throws Exception {
    final Map<Clazz.MethodDef, Set<Clazz.MethodDef>> using = new TreeMap<Clazz.MethodDef, Set<Clazz.MethodDef>>(COMPARATOR);
    final Map<Clazz.MethodDef, Set<Clazz.MethodDef>> usedby = new TreeMap<Clazz.MethodDef, Set<Clazz.MethodDef>>(COMPARATOR);
    ClassDataCollector cd = new ClassDataCollector() {

        // Clazz.MethodDef source;
        // Before a method is parsed
        @Override
        public void method(Clazz.MethodDef source) {
            // this.source = source;
            xref(using, source, null);
            xref(usedby, source, null);
        }
    };
    for (Clazz clazz : classes) {
        clazz.parseClassFileWithCollector(cd);
    }
    out.println("<calltree>");
    xref(out, "using", using);
    xref(out, "usedby", usedby);
    out.println("</calltree>");
}
Also used : Set(java.util.Set) TreeSet(java.util.TreeSet) MethodDef(aQute.bnd.osgi.Clazz.MethodDef) Clazz(aQute.bnd.osgi.Clazz) TreeMap(java.util.TreeMap) ClassDataCollector(aQute.bnd.osgi.ClassDataCollector)

Example 20 with Clazz

use of aQute.bnd.osgi.Clazz in project bnd by bndtools.

the class XMLAttributeFinder method extractDefaults.

private Map<String, String> extractDefaults(TypeRef name, final Analyzer analyzer) {
    try {
        Clazz clazz = analyzer.findClass(name);
        final Map<String, String> props = new LinkedHashMap<String, String>();
        clazz.parseClassFileWithCollector(new ClassDataCollector() {

            @Override
            public void annotationDefault(Clazz.MethodDef defined) {
                Object value = defined.getConstant();
                // check type, exit with warning if annotation or annotation
                // array
                boolean isClass = false;
                TypeRef type = defined.getType().getClassRef();
                if (!type.isPrimitive()) {
                    if (Class.class.getName().equals(type.getFQN())) {
                        isClass = true;
                    } else {
                        try {
                            Clazz r = analyzer.findClass(type);
                            if (r.isAnnotation()) {
                                analyzer.warning("Nested annotation type found in field %s, %s", defined.getName(), type.getFQN());
                                return;
                            }
                        } catch (Exception e) {
                            analyzer.exception(e, "Exception extracting annotation defaults for type %s", type);
                            return;
                        }
                    }
                }
                if (value != null) {
                    String name = defined.getName();
                    if (value.getClass().isArray()) {
                        StringBuilder sb = new StringBuilder();
                        String sep = "";
                        // add element individually
                        for (int i = 0; i < Array.getLength(value); i++) {
                            Object element = Array.get(value, i);
                            sb.append(sep).append(convert(element, isClass));
                            sep = " ";
                        }
                        props.put(name, sb.toString());
                    } else {
                        props.put(name, convert(value, isClass));
                    }
                }
            }

            private String convert(Object value, boolean isClass) {
                if (isClass)
                    return ((TypeRef) value).getFQN();
                return String.valueOf(value);
            }
        });
        defaultsCache.put(name, props);
        return props;
    } catch (Exception e) {
        analyzer.exception(e, "Exception extracting annotation defaults for type %s", name);
    }
    return null;
}
Also used : TypeRef(aQute.bnd.osgi.Descriptors.TypeRef) Clazz(aQute.bnd.osgi.Clazz) ClassDataCollector(aQute.bnd.osgi.ClassDataCollector) LinkedHashMap(java.util.LinkedHashMap)

Aggregations

Clazz (aQute.bnd.osgi.Clazz)56 Analyzer (aQute.bnd.osgi.Analyzer)14 ClassDataCollector (aQute.bnd.osgi.ClassDataCollector)14 TypeRef (aQute.bnd.osgi.Descriptors.TypeRef)12 PackageRef (aQute.bnd.osgi.Descriptors.PackageRef)8 InputStream (java.io.InputStream)8 FileResource (aQute.bnd.osgi.FileResource)7 File (java.io.File)7 HashMap (java.util.HashMap)7 FileInputStream (java.io.FileInputStream)6 Resource (aQute.bnd.osgi.Resource)5 MethodDef (aQute.bnd.osgi.Clazz.MethodDef)4 Descriptors (aQute.bnd.osgi.Descriptors)4 Instruction (aQute.bnd.osgi.Instruction)4 Jar (aQute.bnd.osgi.Jar)4 IOException (java.io.IOException)4 ArrayList (java.util.ArrayList)4 Map (java.util.Map)4 TreeSet (java.util.TreeSet)4 Parameters (aQute.bnd.header.Parameters)3