Search in sources :

Example 1 with ScannedAnnotation

use of org.apache.felix.scrplugin.annotations.ScannedAnnotation in project felix by apache.

the class ClassScanner method extractAnnotation.

/**
 * Extract annotations
 */
private final List<ScannedAnnotation> extractAnnotation(final ClassNode classNode, final Class<?> annotatedClass) throws SCRDescriptorException {
    final List<ScannedAnnotation> descriptions = new ArrayList<ScannedAnnotation>();
    // first parse class annotations
    @SuppressWarnings("unchecked") final List<AnnotationNode> annotations = getAllAnnotations(classNode.invisibleAnnotations, classNode.visibleAnnotations);
    if (annotations != null) {
        for (final AnnotationNode annotation : annotations) {
            this.parseAnnotation(descriptions, annotation, annotatedClass);
        }
        // second parse method annotations
        @SuppressWarnings("unchecked") final List<MethodNode> methods = classNode.methods;
        if (methods != null) {
            for (final MethodNode method : methods) {
                final String name = method.name;
                // check for constructor
                if (!"<init>".equals(name)) {
                    @SuppressWarnings("unchecked") final List<AnnotationNode> annos = getAllAnnotations(method.invisibleAnnotations, method.visibleAnnotations);
                    if (annos != null) {
                        final Type[] signature = Type.getArgumentTypes(method.desc);
                        final Method[] allMethods = annotatedClass.getDeclaredMethods();
                        Method found = null;
                        for (final Method m : allMethods) {
                            if (m.getName().equals(name)) {
                                if (m.getParameterTypes().length == 0 && (signature == null || signature.length == 0)) {
                                    found = m;
                                }
                                if (m.getParameterTypes().length > 0 && signature != null && m.getParameterTypes().length == signature.length) {
                                    found = m;
                                    for (int index = 0; index < m.getParameterTypes().length; index++) {
                                        String parameterTypeName = m.getParameterTypes()[index].getName();
                                        // Name of array parameters is returned with syntax [L<name>;, convert to <name>[]
                                        Matcher matcher = ARRAY_PARAM_TYPE_NAME.matcher(parameterTypeName);
                                        if (matcher.matches()) {
                                            parameterTypeName = matcher.group(1) + "[]";
                                        }
                                        if (!parameterTypeName.equals(signature[index].getClassName()) && !m.getParameterTypes()[index].getSimpleName().equals(signature[index].getClassName())) {
                                            found = null;
                                        }
                                    }
                                }
                                // if method is found return it now, to avoid resetting 'found' to null if next method has same name but different parameters
                                if (found != null) {
                                    break;
                                }
                            }
                        }
                        if (found == null) {
                            throw new SCRDescriptorException("Annotated method " + name + " not found.", annotatedClass.getName());
                        }
                        for (final AnnotationNode annotation : annos) {
                            parseAnnotation(descriptions, annotation, found);
                        }
                    }
                }
            }
        }
        // third parse field annotations
        @SuppressWarnings("unchecked") final List<FieldNode> fields = classNode.fields;
        if (fields != null) {
            for (final FieldNode field : fields) {
                @SuppressWarnings("unchecked") final List<AnnotationNode> annos = getAllAnnotations(field.invisibleAnnotations, field.visibleAnnotations);
                if (annos != null) {
                    final String name = field.name;
                    final Field[] allFields = annotatedClass.getDeclaredFields();
                    Field found = null;
                    for (final Field f : allFields) {
                        if (f.getName().equals(name)) {
                            found = f;
                            break;
                        }
                    }
                    if (found == null) {
                        throw new SCRDescriptorException("Annotated field " + name + " not found.", annotatedClass.getName());
                    }
                    for (final AnnotationNode annotation : annos) {
                        parseAnnotation(descriptions, annotation, found);
                    }
                }
            }
        }
    }
    return descriptions;
}
Also used : FieldNode(org.objectweb.asm.tree.FieldNode) Matcher(java.util.regex.Matcher) ArrayList(java.util.ArrayList) Method(java.lang.reflect.Method) Field(java.lang.reflect.Field) Type(org.objectweb.asm.Type) MethodNode(org.objectweb.asm.tree.MethodNode) AnnotationNode(org.objectweb.asm.tree.AnnotationNode) ScannedAnnotation(org.apache.felix.scrplugin.annotations.ScannedAnnotation) SCRDescriptorException(org.apache.felix.scrplugin.SCRDescriptorException)

Example 2 with ScannedAnnotation

use of org.apache.felix.scrplugin.annotations.ScannedAnnotation in project felix by apache.

the class SCRAnnotationProcessor method createProperties.

/**
 * Create properties descriptions
 *
 * @throws SCRDescriptorException
 * @throws SCRDescriptorFailureException
 */
private void createProperties(final List<? extends ScannedAnnotation> descs, final ClassDescription describedClass) throws SCRDescriptorFailureException, SCRDescriptorException {
    for (final ScannedAnnotation ad : descs) {
        final PropertyDescription prop = new PropertyDescription(ad);
        // check for field annotation
        final FieldAnnotation fieldAnnotation;
        if (ad instanceof FieldAnnotation) {
            fieldAnnotation = (FieldAnnotation) ad;
        } else {
            fieldAnnotation = null;
        }
        // Detect values from annotation
        String type = null;
        String[] values = null;
        int index = 0;
        while (type == null && index < PROPERTY_VALUE_PROCESSING.length) {
            final String propType = PROPERTY_VALUE_PROCESSING[index];
            final String propName = PROPERTY_VALUE_PROCESSING[index + 1];
            final Object propValue = ad.getValue(propName);
            if (propValue != null && propValue.getClass().isArray()) {
                type = propType;
                values = new String[Array.getLength(propValue)];
                for (int i = 0; i < values.length; i++) {
                    values[i] = Array.get(propValue, i).toString();
                }
            }
            index += 2;
        }
        String name = ad.getStringValue("name", null);
        if (values != null) {
            prop.setType(PropertyType.valueOf(type));
            if (values.length == 1) {
                prop.setValue(values[0]);
            } else {
                prop.setMultiValue(values);
            }
            if (name == null) {
                final Object value = fieldAnnotation.getAnnotatedFieldValue();
                if (value != null) {
                    name = value.toString();
                }
            }
        } else if (fieldAnnotation != null) {
            // Detect values from field
            if (name != null) {
                final Object value = fieldAnnotation.getAnnotatedFieldValue();
                if (value != null) {
                    if (value.getClass().isArray()) {
                        final String[] newValues = new String[Array.getLength(value)];
                        for (int i = 0; i < newValues.length; i++) {
                            newValues[i] = Array.get(value, i).toString();
                        }
                        prop.setMultiValue(newValues);
                        prop.setType(PropertyType.from(fieldAnnotation.getAnnotatedField().getType().getComponentType()));
                    } else {
                        prop.setType(PropertyType.from(value.getClass()));
                        prop.setValue(value.toString());
                    }
                }
            } else {
                if (Modifier.isStatic(fieldAnnotation.getAnnotatedField().getModifiers())) {
                    final Object value = fieldAnnotation.getAnnotatedFieldValue();
                    if (value != null) {
                        name = value.toString();
                    }
                } else {
                    // non static, no name, no value (FELIX-4393)
                    name = fieldAnnotation.getAnnotatedField().getName();
                    final Object value = fieldAnnotation.getAnnotatedFieldValue();
                    if (value != null) {
                        if (value.getClass().isArray()) {
                            final String[] newValues = new String[Array.getLength(value)];
                            for (int i = 0; i < newValues.length; i++) {
                                newValues[i] = Array.get(value, i).toString();
                            }
                            prop.setMultiValue(newValues);
                            prop.setType(PropertyType.from(fieldAnnotation.getAnnotatedField().getType().getComponentType()));
                        } else {
                            prop.setType(PropertyType.from(value.getClass()));
                            prop.setValue(value.toString());
                        }
                    }
                }
            }
        }
        prop.setName(name);
        prop.setLabel(ad.getStringValue("label", null));
        prop.setDescription(ad.getStringValue("description", null));
        // check type
        if (prop.getType() == null) {
            prop.setType(PropertyType.String);
        }
        // private
        if (ad.getValue("propertyPrivate") != null) {
            prop.setPrivate(ad.getBooleanValue("propertyPrivate", false));
        }
        // cardinality handling
        final PropertyUnbounded pu = PropertyUnbounded.valueOf(ad.getEnumValue("unbounded", PropertyUnbounded.DEFAULT.name()));
        prop.setUnbounded(pu);
        if (pu == PropertyUnbounded.DEFAULT) {
            prop.setCardinality(ad.getIntegerValue("cardinality", 0));
            if (prop.getMultiValue() != null && prop.getCardinality() == 0) {
                prop.setUnbounded(PropertyUnbounded.ARRAY);
            }
        } else {
            prop.setCardinality(0);
        }
        if (prop.getValue() != null) {
            if (prop.getUnbounded() == PropertyUnbounded.ARRAY || prop.getUnbounded() == PropertyUnbounded.VECTOR) {
                prop.setMultiValue(new String[] { prop.getValue() });
            } else if (prop.getCardinality() < -1 || prop.getCardinality() > 1) {
                prop.setMultiValue(new String[] { prop.getValue() });
            }
        }
        // options
        final ScannedAnnotation[] options = (ScannedAnnotation[]) ad.getValue("options");
        if (options != null) {
            final List<String> propertyOptions = new ArrayList<String>();
            for (final ScannedAnnotation po : options) {
                propertyOptions.add(po.getStringValue("name", ""));
                propertyOptions.add(po.getStringValue("value", ""));
            }
            prop.setOptions(propertyOptions.toArray(new String[propertyOptions.size()]));
        }
        describedClass.add(prop);
    }
}
Also used : PropertyDescription(org.apache.felix.scrplugin.description.PropertyDescription) FieldAnnotation(org.apache.felix.scrplugin.annotations.FieldAnnotation) ArrayList(java.util.ArrayList) ScannedAnnotation(org.apache.felix.scrplugin.annotations.ScannedAnnotation) PropertyUnbounded(org.apache.felix.scrplugin.description.PropertyUnbounded)

Example 3 with ScannedAnnotation

use of org.apache.felix.scrplugin.annotations.ScannedAnnotation in project felix by apache.

the class SCRAnnotationProcessor method createReferences.

/**
 * Create reference descriptions
 *
 * @param descs
 *            List of reference annotations.s
 * @param describedClass
 *            The described class.
 */
private void createReferences(final List<? extends ScannedAnnotation> descs, final ClassDescription describedClass) {
    for (final ScannedAnnotation ad : descs) {
        final ReferenceDescription ref = new ReferenceDescription(ad);
        // check for field annotation
        final FieldAnnotation fieldAnnotation;
        if (ad instanceof FieldAnnotation) {
            fieldAnnotation = (FieldAnnotation) ad;
            ref.setField(fieldAnnotation.getAnnotatedField());
        } else {
            fieldAnnotation = null;
        }
        ref.setName(ad.getStringValue("name", (fieldAnnotation != null ? fieldAnnotation.getAnnotatedField().getName() : null)));
        String defaultInterfaceName = null;
        if (fieldAnnotation != null) {
            if (fieldAnnotation.getAnnotatedField().getType().isArray()) {
                defaultInterfaceName = fieldAnnotation.getAnnotatedField().getType().getComponentType().getName();
            } else {
                defaultInterfaceName = fieldAnnotation.getAnnotatedField().getType().getName();
            }
        }
        ref.setInterfaceName(ad.getStringValue("referenceInterface", defaultInterfaceName));
        ref.setTarget(ad.getStringValue("target", null));
        ref.setCardinality(ReferenceCardinality.valueOf(ad.getEnumValue("cardinality", ReferenceCardinality.MANDATORY_UNARY.name())));
        ref.setPolicy(ReferencePolicy.valueOf(ad.getEnumValue("policy", ReferencePolicy.STATIC.name())));
        ref.setPolicyOption(ReferencePolicyOption.valueOf(ad.getEnumValue("policyOption", ReferencePolicyOption.RELUCTANT.name())));
        ref.setStrategy(ReferenceStrategy.valueOf(ad.getEnumValue("strategy", ReferenceStrategy.EVENT.name())));
        ref.setBind(ad.getStringValue("bind", null));
        ref.setUnbind(ad.getStringValue("unbind", null));
        ref.setUpdated(ad.getStringValue("updated", null));
        describedClass.add(ref);
    }
}
Also used : ReferenceDescription(org.apache.felix.scrplugin.description.ReferenceDescription) FieldAnnotation(org.apache.felix.scrplugin.annotations.FieldAnnotation) ScannedAnnotation(org.apache.felix.scrplugin.annotations.ScannedAnnotation)

Example 4 with ScannedAnnotation

use of org.apache.felix.scrplugin.annotations.ScannedAnnotation in project felix by apache.

the class ClassScanner method processClass.

/**
 * Scan a single class.
 */
private ClassDescription processClass(final Class<?> annotatedClass, final String location) throws SCRDescriptorFailureException, SCRDescriptorException {
    log.debug("Processing " + annotatedClass.getName());
    try {
        // get the class file for ASM
        final String pathToClassFile = annotatedClass.getName().replace('.', '/') + ".class";
        final InputStream input = project.getClassLoader().getResourceAsStream(pathToClassFile);
        final ClassReader classReader;
        try {
            classReader = new ClassReader(input);
        } finally {
            if (input != null) {
                input.close();
            }
        }
        final ClassNode classNode = new ClassNode();
        classReader.accept(classNode, SKIP_CODE | SKIP_DEBUG | SKIP_FRAMES);
        // create descriptions
        final List<ScannedAnnotation> annotations = extractAnnotation(classNode, annotatedClass);
        if (annotations.size() > 0) {
            // process annotations and create descriptions
            final ClassDescription desc = new ClassDescription(annotatedClass, location);
            aProcessor.process(new ScannedClass(annotations, annotatedClass), desc);
            log.debug("Found descriptions " + desc + " in " + annotatedClass.getName());
            return desc;
        }
    } catch (final IllegalArgumentException ioe) {
        throw new SCRDescriptorException("Unable to scan class files: " + annotatedClass.getName() + " (Class file format probably not supported by ASM ?)", location, ioe);
    } catch (final IOException ioe) {
        throw new SCRDescriptorException("Unable to scan class files: " + annotatedClass.getName(), location, ioe);
    }
    return null;
}
Also used : ClassNode(org.objectweb.asm.tree.ClassNode) FilterInputStream(java.io.FilterInputStream) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) ClassReader(org.objectweb.asm.ClassReader) ScannedAnnotation(org.apache.felix.scrplugin.annotations.ScannedAnnotation) ClassDescription(org.apache.felix.scrplugin.description.ClassDescription) ScannedClass(org.apache.felix.scrplugin.annotations.ScannedClass) IOException(java.io.IOException) SCRDescriptorException(org.apache.felix.scrplugin.SCRDescriptorException)

Example 5 with ScannedAnnotation

use of org.apache.felix.scrplugin.annotations.ScannedAnnotation in project felix by apache.

the class ClassScanner method parseAnnotation.

/**
 * Parse annotation and create a description.
 */
private void parseAnnotation(final List<ScannedAnnotation> descriptions, final AnnotationNode annotation, final Object annotatedObject) {
    // desc has the format 'L' + className.replace('.', '/') + ';'
    final String name = annotation.desc.substring(1, annotation.desc.length() - 1).replace('/', '.');
    Map<String, Object> values = null;
    if (annotation.values != null) {
        values = new HashMap<String, Object>();
        final Iterator<?> i = annotation.values.iterator();
        while (i.hasNext()) {
            final Object vName = i.next();
            Object value = i.next();
            // convert type to class name string
            if (value instanceof Type) {
                value = ((Type) value).getClassName();
            } else if (value instanceof List<?>) {
                final List<?> objects = (List<?>) value;
                if (objects.size() > 0) {
                    if (objects.get(0) instanceof Type) {
                        final String[] classNames = new String[objects.size()];
                        int index = 0;
                        for (final Object v : objects) {
                            classNames[index] = ((Type) v).getClassName();
                            index++;
                        }
                        value = classNames;
                    } else if (objects.get(0) instanceof AnnotationNode) {
                        final List<ScannedAnnotation> innerDesc = new ArrayList<ScannedAnnotation>();
                        for (final Object v : objects) {
                            parseAnnotation(innerDesc, (AnnotationNode) v, annotatedObject);
                        }
                        if (annotatedObject instanceof Method) {
                            value = innerDesc.toArray(new MethodAnnotation[innerDesc.size()]);
                        } else if (annotatedObject instanceof Field) {
                            value = innerDesc.toArray(new FieldAnnotation[innerDesc.size()]);
                        } else {
                            value = innerDesc.toArray(new ClassAnnotation[innerDesc.size()]);
                        }
                    } else {
                        value = convertToArray(objects, objects.get(0).getClass());
                    }
                } else {
                    value = null;
                }
            }
            values.put(vName.toString(), value);
        }
    }
    final ScannedAnnotation a;
    if (annotatedObject instanceof Method) {
        a = new MethodAnnotation(name, values, (Method) annotatedObject);
        ((Method) annotatedObject).setAccessible(true);
    } else if (annotatedObject instanceof Field) {
        a = new FieldAnnotation(name, values, (Field) annotatedObject);
        ((Field) annotatedObject).setAccessible(true);
    } else {
        a = new ClassAnnotation(name, values);
    }
    descriptions.add(a);
}
Also used : ArrayList(java.util.ArrayList) ClassAnnotation(org.apache.felix.scrplugin.annotations.ClassAnnotation) Method(java.lang.reflect.Method) Field(java.lang.reflect.Field) Type(org.objectweb.asm.Type) AnnotationNode(org.objectweb.asm.tree.AnnotationNode) MethodAnnotation(org.apache.felix.scrplugin.annotations.MethodAnnotation) FieldAnnotation(org.apache.felix.scrplugin.annotations.FieldAnnotation) ScannedAnnotation(org.apache.felix.scrplugin.annotations.ScannedAnnotation) ArrayList(java.util.ArrayList) List(java.util.List)

Aggregations

ScannedAnnotation (org.apache.felix.scrplugin.annotations.ScannedAnnotation)5 ArrayList (java.util.ArrayList)3 FieldAnnotation (org.apache.felix.scrplugin.annotations.FieldAnnotation)3 Field (java.lang.reflect.Field)2 Method (java.lang.reflect.Method)2 SCRDescriptorException (org.apache.felix.scrplugin.SCRDescriptorException)2 Type (org.objectweb.asm.Type)2 AnnotationNode (org.objectweb.asm.tree.AnnotationNode)2 FileInputStream (java.io.FileInputStream)1 FilterInputStream (java.io.FilterInputStream)1 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 List (java.util.List)1 Matcher (java.util.regex.Matcher)1 ClassAnnotation (org.apache.felix.scrplugin.annotations.ClassAnnotation)1 MethodAnnotation (org.apache.felix.scrplugin.annotations.MethodAnnotation)1 ScannedClass (org.apache.felix.scrplugin.annotations.ScannedClass)1 ClassDescription (org.apache.felix.scrplugin.description.ClassDescription)1 PropertyDescription (org.apache.felix.scrplugin.description.PropertyDescription)1 PropertyUnbounded (org.apache.felix.scrplugin.description.PropertyUnbounded)1