- Reworked design of the runtime bundle.
- Reworked design of the annotation scanner.
- Replaced proprietary runtime parser by JSON.
- Fixed BundleDependency.
- Allow to configure annotated service dependency filters from config admin (work in progress).
- Reworked Logging.
- Allow to specify service property arrays.



git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@947379 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/annotation/LICENSE.json b/dependencymanager/annotation/LICENSE.json
new file mode 100644
index 0000000..87d1411
--- /dev/null
+++ b/dependencymanager/annotation/LICENSE.json
@@ -0,0 +1,21 @@
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/dependencymanager/annotation/pom.xml b/dependencymanager/annotation/pom.xml
index c3bab2d..da380f3 100644
--- a/dependencymanager/annotation/pom.xml
+++ b/dependencymanager/annotation/pom.xml
@@ -79,6 +79,13 @@
       <version>2.0</version>
       <scope>compile</scope>
     </dependency>
+
+    <dependency>
+       <groupId>org.json</groupId>
+       <artifactId>json</artifactId>
+       <version>20070829</version>
+       <scope>compile</scope>
+    </dependency>
   </dependencies>
 
   <build>
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Property.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Property.java
index 6800747..c87d7e8 100644
--- a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Property.java
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Property.java
@@ -25,7 +25,7 @@
 
 /**
  * Annotation used to describe a property key-value pair. It is used when
- * declaring {@link Service#properties()} attribute, as well as {@link PropertyMetaData#options()} attribute.
+ * declaring {@link Service#properties()} attribute.
  */
 @Retention(RetentionPolicy.CLASS)
 @Target( { ElementType.ANNOTATION_TYPE })
@@ -41,5 +41,11 @@
      * Returns the property value
      * @return this property value
      */
-    String value();
+    String value() default "";
+    
+    /**
+     * Returns the property values as a String array).
+     * @return this property value as a String array
+     */
+    String[] values() default {};
 }
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/PropertyMetaData.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/PropertyMetaData.java
index 5c41695..a955ef3 100644
--- a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/PropertyMetaData.java
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/PropertyMetaData.java
@@ -106,10 +106,16 @@
     boolean required() default true;
 
     /**
-     * Return a list of valid options for this property.
-     * The Options are defined using the {@link Property} annotation, where the {@link Property#name()} attribute is used to
-     * reference the option label, and the {@link Property#value()} attribute is used to reference the option value.
-     * @return the list of valid options for this property.
+     * Return a list of valid option labels for this property. The purpose of this method is to allow menus with localized labels.
+     * It is associated with the {@link #optionValues()} attribute. The labels returned here are ordered in the same way as the 
+     * {@link #optionValues()} attribute values. 
+     * @return the list of valid option labels for this property.
      */
-    Property[] options() default {};
+    String[] optionLabels() default {};
+    
+    /**
+     * Return a list of option values that this property can take. This list must be in the same sequence as the {@link #optionLabels()} 
+     * attribute.
+     */
+   String[] optionValues() default {};
 }
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Service.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Service.java
index 8abbf91..725e588 100644
--- a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Service.java
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Service.java
@@ -102,7 +102,7 @@
  *    *&#47;
  *  &#64;Service 
  *  class Y {
- *      &#64;ServiceDependency(filter="(dm.factory.name=MyServiceFactory))
+ *      &#64;ServiceDependency(filter="(dm.factory.name=MyServiceFactory)")
  *      Set&lt;Dictionary&gt; _XFactory; // This Set acts as a Factory API for creating X Service instances.
  *    
  *      &#64;Start
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/dependency/ServiceDependency.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/dependency/ServiceDependency.java
index adac069..85bb686 100644
--- a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/dependency/ServiceDependency.java
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/dependency/ServiceDependency.java
@@ -32,42 +32,38 @@
 public @interface ServiceDependency
 {
     /**
-     * Returns the Service dependency type (by default, the type is method parameter type).
-     * @return the Service dependency type.
+     * The type if the service this dependency is applying on. By default, the type is method parameter or the class field type.
      */
     Class<?> service() default Object.class;
 
     /**
-     * Returns the Service dependency OSGi filter.
-     * @return The Service dependency filter.
+     * The Service dependency OSGi filter.
      */
     String filter() default "";
 
     /**
-     * Returns the class for the default implementation, if the dependency is not available.
-     * @return The default class used when the dependency is not available.
+     * The class for the default implementation, if the dependency is not available.
      */
     Class<?> defaultImpl() default Object.class;
 
     /**
-     * Returns whether the Service dependency is required or not.
-     * @return true if the dependency is required, false if not.
+     * Whether the Service dependency is required or not.
      */
     boolean required() default true;
 
     /**
-     * Returns the callback method to be invoked when the service is available. This attribute is only meaningful when 
+     * The callback method to be invoked when the service is available. This attribute is only meaningful when 
      * the annotation is applied on a class field.
      */
     String added() default "";
 
     /**
-     * Returns the callback method to be invoked when the service properties have changed.
+     * The callback method to be invoked when the service properties have changed.
      */
     String changed() default "";
 
     /**
-     * Returns the callback method to invoke when the service is lost.
+     * The callback method to invoke when the service is lost.
      */
     String removed() default "";
 }
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
index 105e7c9..a192057 100644
--- a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
@@ -26,8 +26,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import org.apache.felix.dm.annotation.api.AspectService;
 import org.apache.felix.dm.annotation.api.Composition;
@@ -95,7 +93,7 @@
     private String m_method;
     private String m_descriptor;
     private Set<String> m_methods = new HashSet<String>();
-    private List<Info> m_infos = new ArrayList<Info>(); // Last elem is either Service or AspectService
+    private List<EntryWriter> m_writers = new ArrayList<EntryWriter>(); // Last elem is either Service or AspectService
     private MetaType m_metaType;
     private String m_startMethod;
     private String m_stopMethod;
@@ -103,193 +101,10 @@
     private String m_destroyMethod;
     private String m_compositionMethod;
 
-    // Pattern used to parse the class parameter from the bind methods ("bind(Type)" or "bind(Map, Type)" or "bind(BundleContext, Type)"
-    private final static Pattern m_bindClassPattern = Pattern.compile("\\((L[^;]+;)?L([^;]+);\\)V");
-
-    // Pattern used to parse classes from class descriptors;
-    private final static Pattern m_classPattern = Pattern.compile("L([^;]+);");
-
-    // Pattern used to check if a method is void and does not take any params
-    private final static Pattern m_voidMethodPattern = Pattern.compile("\\(\\)V");
-
-    // Pattern used to check if a method returns an array of Objects
-    private final static Pattern m_methodCompoPattern = Pattern.compile("\\(\\)\\[Ljava/lang/Object;");
-
-    // List of component descriptor entry types
-    enum EntryTypes
-    {
-        Service, 
-        AspectService,
-        AdapterService,
-        BundleAdapterService,
-        ResourceAdapterService,
-        FactoryConfigurationAdapterService,
-        ServiceDependency, 
-        TemporalServiceDependency, 
-        ConfigurationDependency,
-        BundleDependency,
-        ResourceDependency,
-    };
-
-    // List of component descriptor parameters
-    enum Params
-    {
-        init, 
-        start, 
-        stop, 
-        destroy, 
-        impl, 
-        provide, 
-        properties, 
-        composition, 
-        service, 
-        filter, 
-        defaultImpl, 
-        required, 
-        added, 
-        changed,
-        removed,
-        autoConfig, 
-        pid, 
-        factoryPid,
-        propagate, 
-        updated, 
-        timeout,
-        adapterService,
-        adapterProperties,
-        adapteeService,
-        adapteeFilter,
-        stateMask,
-        ranking,
-        factory,
-        factoryConfigure,
-    };
-
     /**
-     * This class represents a parsed DependencyManager component descriptor entry.
-     * (either a Service, a ServiceDependency, or a ConfigurationDependency descriptor entry).
+     * This class represents a DependencyManager component descriptor entry.
+     * (Service, a ServiceDependency ... see EntryType enum).
      */
-    private class Info
-    {
-        /** The component descriptor entry type: either Service, (Temporal)ServiceDependency, or ConfigurationDependency */
-        EntryTypes m_entry;
-
-        /** The component descriptor entry parameters (init/start/stop ...) */
-        Map<Params, Object> m_params = new HashMap<Params, Object>();
-
-        /**
-         * Makes a new component descriptor entry.
-         * @param entry the component descriptor entry type (either Service, ServiceDependency, or ConfigurationDependency)
-         */
-        Info(EntryTypes entry)
-        {
-            m_entry = entry;
-        }
-
-        /**
-         * Returns a string representation for the given component descriptor line entry.
-         */
-        @Override
-        public String toString()
-        {
-            StringBuilder sb = new StringBuilder();
-            sb.append(m_entry);
-            sb.append(":").append(" ");
-            for (Map.Entry<Params, Object> e : m_params.entrySet())
-            {
-                sb.append(e.getKey());
-                sb.append("=");
-                sb.append(e.getValue());
-                sb.append("; ");
-            }
-            return sb.toString();
-        }
-
-        /**
-         * Adds a parameter to this component descriptor entry.
-         * @param param the param name
-         * @param value the param value
-         */
-        void addParam(Params param, String value)
-        {
-            String old = (String) m_params.get(param);
-            if (old != null)
-            {
-                value = old + "," + value;
-            }
-            m_params.put(param, value);
-        }
-
-        /**
-         * Adds an annotation parameter to this component descriptor entry.
-         * @param annotation the annotation where the parameter has been parsed
-         * @param param the param name
-         * @param def the default value to add, if the param is not present in the parsed annotation.
-         */
-        void addParam(Annotation annotation, Params param, Object def)
-        {
-            Object value = annotation.get(param.toString());
-            if (value == null && def != null)
-            {
-                value = def;
-            }
-            if (value != null)
-            {
-                if (value instanceof Object[])
-                {
-                    for (Object v : ((Object[]) value))
-                    {
-                        addParam(param, v.toString());
-                    }
-                }
-                else
-                {
-                    addParam(param, value.toString());
-                }
-            }
-        }
-
-        /**
-         * Adds a annotation parameter of type 'class' to this component descriptor entry.
-         * The parsed class parameter has the format "Lfull.package.ClassName;"
-         * @param annotation the annotation where the class parameter has been parsed
-         * @param param the annotation class param name
-         * @param def the default class name to add if the param is not present in the parsed annotation.
-         */
-        void addClassParam(Annotation annotation, Params param, Object def)
-        {
-            Pattern pattern = m_classPattern;
-            Object value = annotation.get(param.toString());
-            if (value == null && def != null)
-            {
-                value = def;
-                pattern = null;
-            }
-            if (value != null)
-            {
-                if (value instanceof Object[])
-                {
-                    for (Object v : ((Object[]) value))
-                    {
-                        if (pattern != null)
-                        {
-                            v = parseClass(v.toString(), pattern, 1);
-                        }
-                        addParam(param, v.toString());
-                    }
-                }
-                else
-                {
-                    if (pattern != null)
-                    {
-                        value = parseClass(value.toString(), pattern, 1);
-                    }
-                    addParam(param, value.toString());
-                }
-            }
-
-        }
-    }
 
     /**
      * Makes a new Collector for parsing a given class.
@@ -368,11 +183,11 @@
     public void annotation(Annotation annotation)
     {
         m_reporter.trace("Parsed annotation: %s", annotation);
-        
+
         if (annotation.getName().equals(A_SERVICE))
         {
             parseServiceAnnotation(annotation);
-        } 
+        }
         else if (annotation.getName().equals(A_ASPECT_SERVICE))
         {
             parseAspectService(annotation);
@@ -395,27 +210,31 @@
         }
         else if (annotation.getName().equals(A_INIT))
         {
-            checkMethod(m_voidMethodPattern);
+            //Patterns.parseMethod(m_method, m_descriptor, Patterns.VOID);
+            // TODO check if method takes optional params like Service, DependencyManager, etc ...
             m_initMethod = m_method;
         }
         else if (annotation.getName().equals(A_START))
         {
-            checkMethod(m_voidMethodPattern);
+            //Patterns.parseMethod(m_method, m_descriptor, Patterns.VOID);
+            // TODO check if method takes optional params like Service, DependencyManager, etc ...
             m_startMethod = m_method;
         }
         else if (annotation.getName().equals(A_STOP))
         {
-            checkMethod(m_voidMethodPattern);
+            //Patterns.parseMethod(m_method, m_descriptor, Patterns.VOID);
+            // TODO check if method takes optional params like Service, DependencyManager, etc ...
             m_stopMethod = m_method;
         }
         else if (annotation.getName().equals(A_DESTROY))
         {
-            checkMethod(m_voidMethodPattern);
+            //Patterns.parseMethod(m_method, m_descriptor, Patterns.VOID);
+            // TODO check if method takes optional params like Service, DependencyManager, etc ...
             m_destroyMethod = m_method;
         }
         else if (annotation.getName().equals(A_COMPOSITION))
         {
-            checkMethod(m_methodCompoPattern);
+            Patterns.parseMethod(m_method, m_descriptor, Patterns.COMPOSITION);
             m_compositionMethod = m_method;
         }
         else if (annotation.getName().equals(A_SERVICE_DEP))
@@ -429,12 +248,12 @@
         else if (annotation.getName().equals(A_TEMPORAL_SERVICE_DEPENDENCY))
         {
             parseServiceDependencyAnnotation(annotation, true);
-        } 
-        else if (annotation.getName().equals(A_BUNDLE_DEPENDENCY)) 
+        }
+        else if (annotation.getName().equals(A_BUNDLE_DEPENDENCY))
         {
             parseBundleDependencyAnnotation(annotation);
         }
-        else if (annotation.getName().equals(A_RESOURCE_DEPENDENCY)) 
+        else if (annotation.getName().equals(A_RESOURCE_DEPENDENCY))
         {
             parseRersourceDependencyAnnotation(annotation);
         }
@@ -446,50 +265,55 @@
      */
     private void parseServiceAnnotation(Annotation annotation)
     {
-        Info info = new Info(EntryTypes.Service);
-        m_infos.add(info);
+        EntryWriter writer = new EntryWriter(EntryType.Service);
+        m_writers.add(writer);
 
         // Register previously parsed Init/Start/Stop/Destroy/Composition annotations
-        addCommonServiceParams(info);
-        
+        addCommonServiceParams(writer);
+
         // impl attribute
-        info.addParam(Params.impl, m_className);
+        writer.put(EntryParam.impl, m_className);
 
         // properties attribute
-        parseParameters(annotation, Params.properties, info);
+        parseProperties(annotation, EntryParam.properties, writer);
 
         // provide attribute
-        info.addClassParam(annotation, Params.provide, m_interfaces);
-        
+        writer.putClassArray(annotation, EntryParam.provide, m_interfaces);
+
         // factory attribute
-        info.addParam(annotation, Params.factory, null);
-        
+        writer.putString(annotation, EntryParam.factory, null);
+
         // factoryPropertiesCallback attribute
-        info.addParam(annotation, Params.factoryConfigure, null);
+        writer.putString(annotation, EntryParam.factoryConfigure, null);
     }
 
-    private void addCommonServiceParams(Info info)
+    private void addCommonServiceParams(EntryWriter writer)
     {
-        if (m_initMethod != null) {
-            info.addParam(Params.init, m_initMethod);
+        if (m_initMethod != null)
+        {
+            writer.put(EntryParam.init, m_initMethod);
         }
-        
-        if (m_startMethod != null) {
-            info.addParam(Params.start, m_startMethod);
+
+        if (m_startMethod != null)
+        {
+            writer.put(EntryParam.start, m_startMethod);
         }
-        
-        if (m_stopMethod != null) {
-            info.addParam(Params.stop, m_stopMethod);
+
+        if (m_stopMethod != null)
+        {
+            writer.put(EntryParam.stop, m_stopMethod);
         }
-        
-        if (m_destroyMethod != null) {
-            info.addParam(Params.destroy, m_destroyMethod);
+
+        if (m_destroyMethod != null)
+        {
+            writer.put(EntryParam.destroy, m_destroyMethod);
         }
-        
+
         // Register Composition method
-        if (m_compositionMethod != null) {
-            info.addParam(Params.composition, m_compositionMethod);
-        }        
+        if (m_compositionMethod != null)
+        {
+            writer.put(EntryParam.composition, m_compositionMethod);
+        }
     }
 
     /**
@@ -498,65 +322,68 @@
      */
     private void parseServiceDependencyAnnotation(Annotation annotation, boolean temporal)
     {
-        Info info = new Info(temporal ? EntryTypes.TemporalServiceDependency
-            : EntryTypes.ServiceDependency);
-        m_infos.add(info);
+        EntryWriter writer = new EntryWriter(temporal ? EntryType.TemporalServiceDependency
+            : EntryType.ServiceDependency);
+        m_writers.add(writer);
 
         // service attribute
-        String service = annotation.get(Params.service.toString());
+        String service = annotation.get(EntryParam.service.toString());
         if (service != null)
         {
-            service = parseClass(service, m_classPattern, 1);
+            service = Patterns.parseClass(service, Patterns.CLASS, 1);
         }
         else
         {
             if (m_isField)
             {
-                service = parseClass(m_descriptor, m_classPattern, 1);
+                service = Patterns.parseClass(m_descriptor, Patterns.CLASS, 1);
             }
             else
             {
-                service = parseClass(m_descriptor, m_bindClassPattern, 2);
+                service = Patterns.parseClass(m_descriptor, Patterns.BIND_CLASS, 2);
             }
         }
-        info.addParam(Params.service, service);
+        writer.put(EntryParam.service, service);
 
         // autoConfig attribute
         if (m_isField)
         {
-            info.addParam(Params.autoConfig, m_field);
+            writer.put(EntryParam.autoConfig, m_field);
         }
 
         // filter attribute
-        String filter = annotation.get(Params.filter.toString());
+        String filter = annotation.get(EntryParam.filter.toString());
         if (filter != null)
         {
             Verifier.verifyFilter(filter, 0);
-            info.addParam(Params.filter, filter);
+            writer.put(EntryParam.filter, filter);
         }
 
         // defaultImpl attribute
-        info.addClassParam(annotation, Params.defaultImpl, null);
+        writer.putClass(annotation, EntryParam.defaultImpl, null);
 
         // added callback
-        info.addParam(annotation, Params.added, (!m_isField) ? m_method : null);
+        writer.putString(annotation, EntryParam.added, (!m_isField) ? m_method : null);
 
         if (temporal)
         {
             // timeout attribute (only valid if parsing a temporal service dependency)
-            info.addParam(annotation, Params.timeout, null);
+            writer.putString(annotation, EntryParam.timeout, null);
         }
         else
         {
             // required attribute (not valid if parsing a temporal service dependency)
-            info.addParam(annotation, Params.required, null);
+            writer.putString(annotation, EntryParam.required, null);
 
             // changed callback
-            info.addParam(annotation, Params.changed, null);
+            writer.putString(annotation, EntryParam.changed, null);
 
             // removed callback
-            info.addParam(annotation, Params.removed, null);
+            writer.putString(annotation, EntryParam.removed, null);
         }
+        
+        // id attribute
+        writer.putString(annotation, EntryParam.name, null);
     }
 
     /**
@@ -565,17 +392,17 @@
      */
     private void parseConfigurationDependencyAnnotation(Annotation annotation)
     {
-        Info info = new Info(EntryTypes.ConfigurationDependency);
-        m_infos.add(info);
+        EntryWriter writer = new EntryWriter(EntryType.ConfigurationDependency);
+        m_writers.add(writer);
 
         // pid attribute
-        info.addParam(annotation, Params.pid, m_className);
+        writer.putString(annotation, EntryParam.pid, m_className);
 
         // propagate attribute
-        info.addParam(annotation, Params.propagate, null);
+        writer.putString(annotation, EntryParam.propagate, null);
 
         // Property Meta Types
-        String pid = get(annotation, Params.pid.toString(), m_className);
+        String pid = get(annotation, EntryParam.pid.toString(), m_className);
         parseMetaTypes(annotation, pid, false);
     }
 
@@ -585,47 +412,52 @@
      */
     private void parseAspectService(Annotation annotation)
     {
-        Info info = new Info(EntryTypes.AspectService);
-        m_infos.add(info);        
+        EntryWriter writer = new EntryWriter(EntryType.AspectService);
+        m_writers.add(writer);
 
         // Register previously parsed Init/Start/Stop/Destroy/Composition annotations
-        addCommonServiceParams(info);
-                
+        addCommonServiceParams(writer);
+
         // Parse service filter
-        String filter = annotation.get(Params.filter.toString());
-        if (filter != null) {
+        String filter = annotation.get(EntryParam.filter.toString());
+        if (filter != null)
+        {
             Verifier.verifyFilter(filter, 0);
-            info.addParam(Params.filter, filter);
+            writer.put(EntryParam.filter, filter);
         }
-        
+
         // Parse service aspect ranking
-        Integer ranking = annotation.get(Params.ranking.toString());
-        info.addParam(Params.ranking, ranking.toString());
-                
+        Integer ranking = annotation.get(EntryParam.ranking.toString());
+        writer.put(EntryParam.ranking, ranking.toString());
+
         // Generate Aspect Implementation
-        info.addParam(Params.impl, m_className);
-        
+        writer.put(EntryParam.impl, m_className);
+
         // Parse Aspect properties.
-        parseParameters(annotation, Params.properties, info);
-        
+        parseProperties(annotation, EntryParam.properties, writer);
+
         // Parse service interface this aspect is applying to
-        Object service = annotation.get(Params.service.toString());
-        if (service == null) {
+        Object service = annotation.get(EntryParam.service.toString());
+        if (service == null)
+        {
             if (m_interfaces == null)
             {
                 throw new IllegalStateException("Invalid AspectService annotation: " +
-                    "the service attribute has not been set and the class " + m_className + " does not implement any interfaces");
+                    "the service attribute has not been set and the class " + m_className
+                    + " does not implement any interfaces");
             }
-            if (m_interfaces.length != 1) 
+            if (m_interfaces.length != 1)
             {
                 throw new IllegalStateException("Invalid AspectService annotation: " +
-                    "the service attribute has not been set and the class " + m_className + " implements more than one interface");
+                    "the service attribute has not been set and the class " + m_className
+                    + " implements more than one interface");
             }
-            
-            info.addParam(Params.service, m_interfaces[0]);
-        } else
+
+            writer.put(EntryParam.service, m_interfaces[0]);
+        }
+        else
         {
-            info.addClassParam(annotation, Params.service, null);
+            writer.putClassArray(annotation, EntryParam.service, null);
         }
     }
 
@@ -633,33 +465,33 @@
      * Parses an AspectService annotation.
      * @param annotation
      */
-    private void parseAdapterService(Annotation annotation) 
+    private void parseAdapterService(Annotation annotation)
     {
-        Info info = new Info(EntryTypes.AdapterService);
-        m_infos.add(info);
-        
+        EntryWriter writer = new EntryWriter(EntryType.AdapterService);
+        m_writers.add(writer);
+
         // Register previously parsed Init/Start/Stop/Destroy/Composition annotations
-        addCommonServiceParams(info);
-        
+        addCommonServiceParams(writer);
+
         // Generate Adapter Implementation
-        info.addParam(Params.impl, m_className);
-      
+        writer.put(EntryParam.impl, m_className);
+
         // Parse adaptee filter
-        String adapteeFilter = annotation.get(Params.adapteeFilter.toString());
+        String adapteeFilter = annotation.get(EntryParam.adapteeFilter.toString());
         if (adapteeFilter != null)
         {
             Verifier.verifyFilter(adapteeFilter, 0);
-            info.addParam(Params.adapteeFilter, adapteeFilter);
+            writer.put(EntryParam.adapteeFilter, adapteeFilter);
         }
-        
+
         // Parse the mandatory adapted service interface.
-        info.addClassParam(annotation, Params.adapteeService, null);
-        
+        writer.putClass(annotation, EntryParam.adapteeService, null);
+
         // Parse Adapter properties.
-        parseParameters(annotation, Params.adapterProperties, info);
+        parseProperties(annotation, EntryParam.adapterProperties, writer);
 
         // Parse the optional adapter service (use directly implemented interface by default).
-        info.addClassParam(annotation, Params.adapterService, m_interfaces);
+        writer.putClassArray(annotation, EntryParam.adapterService, m_interfaces);
     }
 
     /**
@@ -668,34 +500,35 @@
      */
     private void parseBundleAdapterService(Annotation annotation)
     {
-        Info info = new Info(EntryTypes.BundleAdapterService);
-        m_infos.add(info);
-        
+        EntryWriter writer = new EntryWriter(EntryType.BundleAdapterService);
+        m_writers.add(writer);
+
         // Register previously parsed Init/Start/Stop/Destroy/Composition annotations
-        addCommonServiceParams(info);
-        
+        addCommonServiceParams(writer);
+
         // Generate Adapter Implementation
-        info.addParam(Params.impl, m_className);
-      
+        writer.put(EntryParam.impl, m_className);
+
         // Parse bundle filter
-        String filter = annotation.get(Params.filter.toString());
+        String filter = annotation.get(EntryParam.filter.toString());
         if (filter != null)
         {
             Verifier.verifyFilter(filter, 0);
-            info.addParam(Params.filter, filter);
+            writer.put(EntryParam.filter, filter);
         }
-        
+
         // Parse stateMask attribute
-        info.addParam(annotation, Params.stateMask, Integer.valueOf(Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE));
-        
+        writer.putString(annotation, EntryParam.stateMask, Integer.valueOf(
+            Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE).toString());
+
         // Parse Adapter properties.
-        parseParameters(annotation, Params.properties, info);
+        parseProperties(annotation, EntryParam.properties, writer);
 
         // Parse the optional adapter service (use directly implemented interface by default).
-        info.addClassParam(annotation, Params.service, m_interfaces);
-        
+        writer.putClassArray(annotation, EntryParam.service, m_interfaces);
+
         // Parse propagate attribute
-        info.addParam(annotation, Params.propagate, Boolean.FALSE);
+        writer.putString(annotation, EntryParam.propagate, Boolean.FALSE.toString());
     }
 
     /**
@@ -704,31 +537,31 @@
      */
     private void parseResourceAdapterService(Annotation annotation)
     {
-        Info info = new Info(EntryTypes.ResourceAdapterService);
-        m_infos.add(info);
-        
+        EntryWriter writer = new EntryWriter(EntryType.ResourceAdapterService);
+        m_writers.add(writer);
+
         // Register previously parsed Init/Start/Stop/Destroy/Composition annotations
-        addCommonServiceParams(info);
-        
+        addCommonServiceParams(writer);
+
         // Generate Adapter Implementation
-        info.addParam(Params.impl, m_className);
-      
+        writer.put(EntryParam.impl, m_className);
+
         // Parse resource filter
-        String filter = annotation.get(Params.filter.toString());
+        String filter = annotation.get(EntryParam.filter.toString());
         if (filter != null)
         {
             Verifier.verifyFilter(filter, 0);
-            info.addParam(Params.filter, filter);
+            writer.put(EntryParam.filter, filter);
         }
-                
+
         // Parse Adapter properties.
-        parseParameters(annotation, Params.properties, info);
+        parseProperties(annotation, EntryParam.properties, writer);
 
         // Parse the optional adapter service (use directly implemented interface by default).
-        info.addClassParam(annotation, Params.service, m_interfaces);
-        
+        writer.putClassArray(annotation, EntryParam.service, m_interfaces);
+
         // Parse propagate attribute
-        info.addParam(annotation, Params.propagate, Boolean.FALSE);
+        writer.putString(annotation, EntryParam.propagate, Boolean.FALSE.toString());
     }
 
     /**
@@ -737,79 +570,79 @@
      */
     private void parseFactoryConfigurationAdapterService(Annotation annotation)
     {
-        Info info = new Info(EntryTypes.FactoryConfigurationAdapterService);
-        m_infos.add(info);
-        
+        EntryWriter writer = new EntryWriter(EntryType.FactoryConfigurationAdapterService);
+        m_writers.add(writer);
+
         // Register previously parsed Init/Start/Stop/Destroy/Composition annotations
-        addCommonServiceParams(info);
+        addCommonServiceParams(writer);
 
         // Generate Adapter Implementation
-        info.addParam(Params.impl, m_className);
+        writer.put(EntryParam.impl, m_className);
 
         // Parse factory Pid
-        info.addParam(annotation, Params.factoryPid, m_className);
-        
+        writer.putString(annotation, EntryParam.factoryPid, m_className);
+
         // Parse updated callback
-        info.addParam(annotation, Params.updated, "updated");
-        
+        writer.putString(annotation, EntryParam.updated, "updated");
+
         // propagate attribute
-        info.addParam(annotation, Params.propagate, Boolean.FALSE);
-        
+        writer.putString(annotation, EntryParam.propagate, Boolean.FALSE.toString());
+
         // Parse the optional adapter service (use directly implemented interface by default).
-        info.addClassParam(annotation, Params.service, m_interfaces);
+        writer.putClassArray(annotation, EntryParam.service, m_interfaces);
 
         // Parse Adapter properties.
-        parseParameters(annotation, Params.properties, info);
+        parseProperties(annotation, EntryParam.properties, writer);
 
         // Parse optional meta types for configuration description.
-        String factoryPid = get(annotation, Params.factoryPid.toString(), m_className);
-        parseMetaTypes(annotation, factoryPid, true);        
+        String factoryPid = get(annotation, EntryParam.factoryPid.toString(), m_className);
+        parseMetaTypes(annotation, factoryPid, true);
     }
 
-
     private void parseBundleDependencyAnnotation(Annotation annotation)
     {
-        Info info = new Info(EntryTypes.BundleDependency);
-        m_infos.add(info);
+        EntryWriter writer = new EntryWriter(EntryType.BundleDependency);
+        m_writers.add(writer);
 
-        String filter = annotation.get(Params.filter.toString());
+        String filter = annotation.get(EntryParam.filter.toString());
         if (filter != null)
         {
             Verifier.verifyFilter(filter, 0);
-            info.addParam(Params.filter, filter);
+            writer.put(EntryParam.filter, filter);
         }
 
-        info.addParam(annotation, Params.added, m_method);
-        info.addParam(annotation, Params.changed, null); // TODO check if "changed" callback exists
-        info.addParam(annotation, Params.removed, null); // TODO check if "removed" callback exists
-        info.addParam(annotation, Params.required, null);
-        info.addParam(annotation, Params.stateMask, null);
-        info.addParam(annotation, Params.propagate, null);
+        writer.putString(annotation, EntryParam.added, m_method);
+        writer.putString(annotation, EntryParam.changed, null);
+        writer.putString(annotation, EntryParam.removed, null);
+        writer.putString(annotation, EntryParam.required, null);
+        writer.putString(annotation, EntryParam.stateMask, null);
+        writer.putString(annotation, EntryParam.propagate, null);
     }
-    
+
     private void parseRersourceDependencyAnnotation(Annotation annotation)
     {
-        Info info = new Info(EntryTypes.ResourceDependency);
-        m_infos.add(info);
+        EntryWriter writer = new EntryWriter(EntryType.ResourceDependency);
+        m_writers.add(writer);
 
-        String filter = annotation.get(Params.filter.toString());
+        String filter = annotation.get(EntryParam.filter.toString());
         if (filter != null)
         {
             Verifier.verifyFilter(filter, 0);
-            info.addParam(Params.filter, filter);
+            writer.put(EntryParam.filter, filter);
         }
 
-        info.addParam(annotation, Params.added, m_method);
-        info.addParam(annotation, Params.changed, null); // TODO check if "changed" callback exists
-        info.addParam(annotation, Params.removed, null); // TODO check if "removed" callback exists
-        info.addParam(annotation, Params.required, null);
-        info.addParam(annotation, Params.propagate, null);        
+        writer.putString(annotation, EntryParam.added, m_method);
+        writer.putString(annotation, EntryParam.changed, null);
+        writer.putString(annotation, EntryParam.removed, null);
+        writer.putString(annotation, EntryParam.required, null);
+        writer.putString(annotation, EntryParam.propagate, null);
     }
 
     /**
      * Parse optional meta types annotation attributes
      * @param annotation
      */
+    @SuppressWarnings("null")
     private void parseMetaTypes(Annotation annotation, String pid, boolean factory)
     {
         if (annotation.get("metadata") != null)
@@ -818,13 +651,13 @@
             String propertiesDesc = annotation.get("description");
 
             MetaType.OCD ocd = new MetaType.OCD(pid, propertiesHeading, propertiesDesc);
-            for (Object p : (Object[]) annotation.get("metadata"))
+            for (Object p: (Object[]) annotation.get("metadata"))
             {
                 Annotation property = (Annotation) p;
                 String heading = property.get("heading");
                 String id = property.get("id");
                 String type = (String) property.get("type");
-                type = (type != null) ? parseClass(type, m_classPattern, 1) : null;
+                type = (type != null) ? Patterns.parseClass(type, Patterns.CLASS, 1) : null;
                 Object[] defaults = (Object[]) property.get("defaults");
                 String description = property.get("description");
                 Integer cardinality = property.get("cardinality");
@@ -832,16 +665,31 @@
 
                 MetaType.AD ad = new MetaType.AD(id, type, defaults, heading, description,
                     cardinality, required);
-                Object[] options = property.get("options");
-                if (options != null)
+
+                Object[] optionLabels = property.get("optionLabels");
+                Object[] optionValues = property.get("optionValues");
+
+                if (optionLabels == null
+                    && optionValues != null
+                    ||
+                    optionLabels != null
+                    && optionValues == null
+                    ||
+                    (optionLabels != null && optionValues != null && optionLabels.length != optionValues.length))
                 {
-                    for (Object o : (Object[]) property.get("options"))
+                    throw new IllegalArgumentException("invalid option labels/values specified for property "
+                        + id +
+                        " in PropertyMetadata annotation from class " + m_className);
+                }
+
+                if (optionValues != null)
+                {
+                    for (int i = 0; i < optionValues.length; i++)
                     {
-                        Annotation option = (Annotation) o;
-                        ad.add(new MetaType.Option((String) option.get("name"),
-                            (String) option.get("value")));
+                        ad.add(new MetaType.Option(optionValues[i].toString(), optionLabels[i].toString()));
                     }
                 }
+
                 ocd.add(ad);
             }
 
@@ -849,78 +697,63 @@
             MetaType.Designate designate = new MetaType.Designate(pid, factory);
             m_metaType.add(designate);
             m_reporter.warning("Parsed MetaType Properties from class " + m_className);
-        }          
+        }
     }
 
     /**
-     * Parses a Param annotation (which represents a list of key-value pari).
+     * Parses a Property annotation (which represents a list of key-value pair).
      * @param annotation the annotation where the Param annotation is defined
      * @param attribute the attribute name which is of Param type
-     * @param info the Info object where the parsed attributes are written
+     * @param writer the object where the parsed attributes are written
      */
-    private void parseParameters(Annotation annotation, Params attribute, Info info) {
+    private void parseProperties(Annotation annotation, EntryParam attribute, EntryWriter writer)
+    {
         Object[] parameters = annotation.get(attribute.toString());
+        Map<String, Object> properties = new HashMap<String, Object>();
         if (parameters != null)
         {
-            for (Object p : parameters)
+            for (Object p: parameters)
             {
-                Annotation a = (Annotation) p; 
-                String prop = a.get("name") + ":" + a.get("value");
-                info.addParam(attribute, prop);
+                Annotation a = (Annotation) p;
+                String name = (String) a.get("name");
+                String value = (String) a.get("value");
+                if (value != null)
+                {
+                    properties.put(name, value);
+                }
+                else
+                {
+                    Object[] values = a.get("values");
+                    if (values != null)
+                    {
+                        // the values is an Object array of actual strings, and we must convert it into a String array.
+                        properties.put(name, Arrays.asList(values).toArray(new String[values.length]));
+                    }
+                    else
+                    {
+                        throw new IllegalArgumentException("Invalid Property attribyte \"" + attribute
+                            + " from annotation " + annotation + " in class " + m_className);
+                    }
+                }
             }
-        }
-    }
-    
-    /**
-     * Parses a class.
-     * @param clazz the class to be parsed (the package is "/" separated).
-     * @param pattern the pattern used to match the class.
-     * @param group the pattern group index where the class can be retrieved.
-     * @return the parsed class.
-     */
-    private String parseClass(String clazz, Pattern pattern, int group)
-    {
-        Matcher matcher = pattern.matcher(clazz);
-        if (matcher.matches())
-        {
-            return matcher.group(group).replace("/", ".");
-        }
-        else
-        {
-            m_reporter.warning("Invalid class descriptor: %s", clazz);
-            throw new IllegalArgumentException("Invalid class descriptor: " + clazz);
+            writer.putProperties(attribute, properties);
         }
     }
 
     /**
-     * Checks if a method descriptor matches a given pattern. 
-     * @param pattern the pattern used to check the method signature descriptor
-     * @throws IllegalArgumentException if the method signature descriptor does not match the given pattern.
-     */
-    private void checkMethod(Pattern pattern)
-    {
-        Matcher matcher = pattern.matcher(m_descriptor);
-        if (!matcher.matches())
-        {
-            m_reporter.warning("Invalid method %s : wrong signature: %s", m_method, m_descriptor);
-            throw new IllegalArgumentException("Invalid method " + m_method + ", wrong signature: "
-                + m_descriptor);
-        }
-    }
-    
-    /**
      * Checks if the class is annotated with some given annotations. Notice that the Service
-     * is always parsed at end of parsing, so, we have to check the last element of our m_infos
+     * is always parsed at end of parsing, so, we have to check the last element of our m_writers
      * List.
      * @return true if one of the provided annotations has been found from the parsed class.
      */
-    private void checkServiceDeclared(EntryTypes ... types) {
+    private void checkServiceDeclared(EntryType... types)
+    {
         boolean ok = false;
-        if (m_infos.size() > 0)
+        if (m_writers.size() > 0)
         {
-            for (EntryTypes type : types)
+            for (EntryType type: types)
             {
-                if (m_infos.get(m_infos.size() - 1).m_entry == type)
+                if (m_writers.get(m_writers.size() - 1).getEntryType() == type)
                 {
                     ok = true;
                     break;
@@ -944,6 +777,7 @@
      * @param defaultValue the default value to return if the attribute is not found in the annotation
      * @return the annotation attribute value, or the defaultValue if not found
      */
+    @SuppressWarnings("unchecked")
     private <T> T get(Annotation properties, String name, T defaultValue)
     {
         T value = (T) properties.get(name);
@@ -956,21 +790,22 @@
      */
     public boolean finish()
     {
-        if (m_infos.size() == 0)
+        if (m_writers.size() == 0)
         {
             return false;
         }
 
         // We must have at least a Service or an AspectService annotation.
-        checkServiceDeclared(EntryTypes.Service, EntryTypes.AspectService, EntryTypes.AdapterService, EntryTypes.BundleAdapterService,
-            EntryTypes.ResourceAdapterService, EntryTypes.FactoryConfigurationAdapterService);
+        checkServiceDeclared(EntryType.Service, EntryType.AspectService, EntryType.AdapterService,
+            EntryType.BundleAdapterService,
+            EntryType.ResourceAdapterService, EntryType.FactoryConfigurationAdapterService);
 
         StringBuilder sb = new StringBuilder();
         sb.append("Parsed annotation for class ");
         sb.append(m_className);
-        for (int i = m_infos.size() - 1; i >= 0; i--)
+        for (int i = m_writers.size() - 1; i >= 0; i--)
         {
-            sb.append("\n\t").append(m_infos.get(i).toString());
+            sb.append("\n\t").append(m_writers.get(i).toString());
         }
         m_reporter.warning(sb.toString());
         return true;
@@ -983,10 +818,10 @@
      */
     public void writeTo(PrintWriter pw)
     {
-        // The last element our our m_infos list contains either the Service, or the AspectService descriptor.
-        for (int i = m_infos.size() - 1; i >= 0; i--)
+        // The last element our our m_writers list contains either the Service, or the AspectService descriptor.
+        for (int i = m_writers.size() - 1; i >= 0; i--)
         {
-            pw.println(m_infos.get(i).toString());
+            pw.println(m_writers.get(i).toString());
         }
     }
 }
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryParam.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryParam.java
new file mode 100644
index 0000000..703effd
--- /dev/null
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryParam.java
@@ -0,0 +1,38 @@
+package org.apache.felix.dm.annotation.plugin.bnd;
+
+/**
+ * The type of parameters which can be found in a component descriptor.
+ */
+public enum EntryParam
+{
+    init, 
+    start, 
+    stop, 
+    destroy, 
+    impl, 
+    provide, 
+    properties, 
+    composition, 
+    service, 
+    filter, 
+    defaultImpl, 
+    required, 
+    added, 
+    changed,
+    removed,
+    autoConfig, 
+    pid, 
+    factoryPid,
+    propagate, 
+    updated, 
+    timeout,
+    adapterService,
+    adapterProperties,
+    adapteeService,
+    adapteeFilter,
+    stateMask,
+    ranking,
+    factory,
+    factoryConfigure,
+    name
+}
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryType.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryType.java
new file mode 100644
index 0000000..bdbd005
--- /dev/null
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryType.java
@@ -0,0 +1,19 @@
+package org.apache.felix.dm.annotation.plugin.bnd;
+
+/**
+ * The type of each entry (lines) stored in a component descriptor.
+ */
+public enum EntryType
+{
+    Service, 
+    AspectService,
+    AdapterService,
+    BundleAdapterService,
+    ResourceAdapterService,
+    FactoryConfigurationAdapterService,
+    ServiceDependency, 
+    TemporalServiceDependency, 
+    ConfigurationDependency,
+    BundleDependency,
+    ResourceDependency,
+}
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryWriter.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryWriter.java
new file mode 100644
index 0000000..3e5c8c7
--- /dev/null
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryWriter.java
@@ -0,0 +1,251 @@
+package org.apache.felix.dm.annotation.plugin.bnd;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import aQute.lib.osgi.Annotation;
+
+/**
+ * This class encodes a component descriptor entry line, using json.
+ */
+public class EntryWriter
+{
+    // Every descriptor entries contains a type parameter for identifying the kind of entry
+    private final static String TYPE = "type";
+
+    /** All parameters as stored in a json object */
+    private JSONObject m_json;
+
+    /** The entry type */
+    private EntryType m_type;
+
+    /**
+     * Makes a new component descriptor entry.
+     */
+    public EntryWriter(EntryType type)
+    {
+        m_type = type;
+        m_json = new JSONObject();
+        try
+        {
+            m_json.put("type", type.toString());
+        }
+        catch (JSONException e)
+        {
+            throw new RuntimeException("could not initialize json object", e);
+        }
+    }
+
+    /**
+     * Returns this entry type.
+     */
+    EntryType getEntryType()
+    {
+        return m_type;
+    }
+
+    /**
+     * Returns a string representation for the given component descriptor entry.
+     */
+    @Override
+    public String toString()
+    {
+        return m_json.toString();
+    }
+
+    /**
+     * Put a String parameter in this descritor entry.
+     */
+    public void put(EntryParam param, String value)
+    {
+        checkType(param.toString());
+        try
+        {
+            m_json.put(param.toString(), value);
+        }
+        catch (JSONException e)
+        {
+            throw new IllegalArgumentException("could not add param " + param + ":" + value, e);
+        }
+    }
+
+    /**
+     * Put a String[] parameter in this descriptor entry.
+     */
+    public void put(EntryParam param, String[] array)
+    {
+        checkType(param.toString());
+        try
+        {
+            m_json.put(param.toString(), new JSONArray(Arrays.asList(array)));
+        }
+        catch (JSONException e)
+        {
+            throw new IllegalArgumentException("could not add param " + param + ":"
+                + Arrays.toString(array), e);
+        }
+    }
+
+    /**
+     * Put a Map parameter in the descriptor entry. The map values must be either Strings or Strings arrays.
+     */
+    public void putProperties(EntryParam param, Map<String, Object> properties)
+    {
+        checkType(param.toString());
+
+        try
+        {
+            JSONObject props = new JSONObject();
+            for (String key: properties.keySet())
+            {
+                Object value = properties.get(key);
+                if (value instanceof String)
+                {
+                    props.put(key, value);
+                }
+                else if (value instanceof String[])
+                {
+                    props.put(key, new JSONArray(Arrays.asList((String[]) value)));
+                }
+                else
+                {
+                    throw new IllegalArgumentException("invalid property value: " + value);
+                }
+            }
+            m_json.put(param.toString(), props);
+        }
+
+        catch (JSONException e)
+        {
+            throw new IllegalArgumentException("invalid properties for " + param + ": "
+                + properties, e);
+        }
+    }
+
+    /**
+     * Get a String attribute value from an annotation and write it into this descriptor entry.
+     */
+    public void putString(Annotation annotation, EntryParam param, String def)
+    {
+        checkType(param.toString());
+        Object value = annotation.get(param.toString());
+        if (value == null && def != null)
+        {
+            value = def;
+        }
+        if (value != null)
+        {
+            put(param, value.toString());
+        }
+    }
+
+    /**
+     * Get a String array attribute value from an annotation and write it into this descriptor entry.
+     */
+    public void putStringArray(Annotation annotation, EntryParam param, String[] def)
+    {
+        checkType(param.toString());
+        Object value = annotation.get(param.toString());
+        if (value == null && def != null)
+        {
+            value = def;
+        }
+        if (value != null)
+        {
+            for (Object v: ((Object[]) value))
+            {
+                try
+                {
+                    m_json.append(param.toString(), v.toString());
+                }
+                catch (JSONException e)
+                {
+                    throw new IllegalArgumentException("Could not add param " + param + ":"
+                        + value.toString(), e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Get a class attribute value from an annotation and write it into this descriptor entry.
+     */
+    public void putClass(Annotation annotation, EntryParam param, Object def)
+    {
+        checkType(param.toString());
+
+        Pattern pattern = Patterns.CLASS;
+        Object value = annotation.get(param.toString());
+        if (value == null && def != null)
+        {
+            value = def;
+            pattern = null;
+        }
+        if (value != null)
+        {
+            if (pattern != null)
+            {
+                value = Patterns.parseClass(value.toString(), pattern, 1);
+            }
+            put(param, value.toString());
+        }
+    }
+
+    /**
+     * Get a class array attribute value from an annotation and write it into this descriptor entry.
+     */
+    public void putClassArray(Annotation annotation, EntryParam param, Object def)
+    {
+        checkType(param.toString());
+
+        Pattern pattern = Patterns.CLASS;
+        Object value = annotation.get(param.toString());
+        if (value == null && def != null)
+        {
+            value = def;
+            pattern = null;
+        }
+        if (value != null)
+        {
+            if (!(value instanceof Object[]))
+            {
+                throw new IllegalArgumentException("annotation parameter " + param
+                    + " has not a class array type");
+            }
+
+            for (Object v: ((Object[]) value))
+            {
+                if (pattern != null)
+                {
+                    v = Patterns.parseClass(v.toString(), pattern, 1);
+                }
+                try
+                {
+                    m_json.append(param.toString(), v.toString());
+                }
+                catch (JSONException e)
+                {
+                    throw new IllegalArgumentException("Could not add param " + param + ":"
+                            + value.toString(), e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Check if the written key is not equals to "type" ("type" is an internal attribute we are using
+     * in order to identify a kind of descriptor entry (Service, ServiceDependency, etc ...).
+     */
+    private void checkType(String key)
+    {
+        if (TYPE.equals(key))
+        {
+            throw new IllegalArgumentException("\"" + TYPE + "\" parameter can't be overriden");
+        }
+    }
+}
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/Patterns.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/Patterns.java
new file mode 100644
index 0000000..7e9b15b
--- /dev/null
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/Patterns.java
@@ -0,0 +1,54 @@
+package org.apache.felix.dm.annotation.plugin.bnd;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Patterns
+{
+    // Pattern used to check if a method is void and does not take any params
+    public final static Pattern VOID = Pattern.compile("\\(\\)V");
+
+    // Pattern used to check if a method returns an array of Objects
+    public final static Pattern COMPOSITION = Pattern.compile("\\(\\)\\[Ljava/lang/Object;");
+
+   // Pattern used to parse the class parameter from the bind methods ("bind(Type)" or "bind(Map, Type)" or "bind(BundleContext, Type)"
+    public final static Pattern BIND_CLASS = Pattern.compile("\\((L[^;]+;)?L([^;]+);\\)V");
+
+    // Pattern used to parse classes from class descriptors;
+    public final static Pattern CLASS = Pattern.compile("L([^;]+);");
+
+    /**
+     * Parses a class.
+     * @param clazz the class to be parsed (the package is "/" separated).
+     * @param pattern the pattern used to match the class.
+     * @param group the pattern group index where the class can be retrieved.
+     * @return the parsed class.
+     */
+    public static String parseClass(String clazz, Pattern pattern, int group)
+    {
+        Matcher matcher = pattern.matcher(clazz);
+        if (matcher.matches())
+        {
+            return matcher.group(group).replace("/", ".");
+        }
+        else
+        {
+            throw new IllegalArgumentException("Invalid class descriptor: " + clazz);
+        }
+    }
+    
+    /**
+     * Checks if a method descriptor matches a given pattern. 
+     * @param pattern the pattern used to check the method signature descriptor
+     * @throws IllegalArgumentException if the method signature descriptor does not match the given pattern.
+     */
+    public static void parseMethod(String method, String descriptor, Pattern pattern)
+    {
+        Matcher matcher = pattern.matcher(descriptor);
+        if (!matcher.matches())
+        {
+            throw new IllegalArgumentException("Invalid method " + method + ", wrong signature: "
+                + descriptor);
+        }
+    }
+}