[Git][java-team/jboss-modules][upstream] New upstream version 1.9.0

Markus Koschany gitlab at salsa.debian.org
Mon Jan 21 22:38:11 GMT 2019


Markus Koschany pushed to branch upstream at Debian Java Maintainers / jboss-modules


Commits:
11aee39d by Markus Koschany at 2019-01-21T22:24:31Z
New upstream version 1.9.0
- - - - -


10 changed files:

- − out/production/jboss-modules-example/example/Main.class
- pom.xml
- + src/main/java/org/jboss/modules/ClassDefiner.java
- src/main/java/org/jboss/modules/ModuleClassLoader.java
- src/main/java/org/jboss/modules/xml/ModuleXmlParser.java
- + src/main/resources/schema/module-1_9.xsd
- + src/test/java/org/jboss/modules/ClassDefinerTest.java
- src/test/java/org/jboss/modules/ModulePropertyTest.java
- + src/test/resources/test/GeneratedClass.class
- + src/test/resources/test/repo/test/dep-props/main/module.xml


Changes:

=====================================
out/production/jboss-modules-example/example/Main.class deleted
=====================================
Binary files a/out/production/jboss-modules-example/example/Main.class and /dev/null differ


=====================================
pom.xml
=====================================
@@ -23,7 +23,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.jboss.modules</groupId>
     <artifactId>jboss-modules</artifactId>
-    <version>1.8.7.Final</version>
+    <version>1.9.0.Final</version>
     <name>JBoss Modules</name>
 
     <parent>


=====================================
src/main/java/org/jboss/modules/ClassDefiner.java
=====================================
@@ -0,0 +1,181 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2018 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jboss.modules;
+
+import java.nio.ByteBuffer;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+
+import static java.security.AccessController.doPrivileged;
+
+/**
+ * A hook for frameworks which need to define additional classes to a module's class loader.
+ */
+public final class ClassDefiner {
+    private static final ClassDefiner instance = new ClassDefiner();
+    private static final RuntimePermission createClassLoaderPermission = new RuntimePermission("createClassLoader");
+
+    private ClassDefiner() {}
+
+    /**
+     * Define a class using the module and protection domain of an existing class.
+     *
+     * @param originalClass the existing class (must not be {@code null})
+     * @param className the new class name (must not be {@code null})
+     * @param classBytes the new class bytes (must not be {@code null})
+     * @return the defined class (not {@code null})
+     */
+    public Class<?> defineClass(Class<?> originalClass, String className, ByteBuffer classBytes) {
+        return defineClass(originalClass, className, getProtectionDomain(originalClass), classBytes);
+    }
+
+    /**
+     * Define a class using the module and protection domain of an existing class.
+     *
+     * @param originalClass the existing class (must not be {@code null})
+     * @param className the new class name (must not be {@code null})
+     * @param classBytes the new class bytes (must not be {@code null})
+     * @param off the offset into the {@code classBytes} array
+     * @param len the number of bytes to use from the {@code classBytes} array
+     * @return the defined class (not {@code null})
+     */
+    public Class<?> defineClass(Class<?> originalClass, String className, byte[] classBytes, int off, int len) {
+        return defineClass(originalClass, className, getProtectionDomain(originalClass), classBytes, off, len);
+    }
+
+    /**
+     * Define a class using the module and protection domain of an existing class.
+     *
+     * @param originalClass the existing class (must not be {@code null})
+     * @param className the new class name (must not be {@code null})
+     * @param classBytes the new class bytes (must not be {@code null})
+     * @return the defined class (not {@code null})
+     */
+    public Class<?> defineClass(Class<?> originalClass, String className, byte[] classBytes) {
+        return defineClass(originalClass, className, getProtectionDomain(originalClass), classBytes, 0, classBytes.length);
+    }
+
+    /**
+     * Define a class using the module of an existing class.
+     *
+     * @param originalClass the existing class (must not be {@code null})
+     * @param className the new class name (must not be {@code null})
+     * @param protectionDomain the protection domain of the new class (must not be {@code null})
+     * @param classBytes the new class bytes (must not be {@code null})
+     * @return the defined class (not {@code null})
+     */
+    public Class<?> defineClass(Class<?> originalClass, String className, ProtectionDomain protectionDomain, ByteBuffer classBytes) {
+        final Module module = Module.forClass(originalClass);
+        if (module == null) throw new IllegalArgumentException("Original " + originalClass + " does not have a module");
+        return module.getClassLoaderPrivate().defineClassInternal(className, classBytes, protectionDomain);
+    }
+
+    /**
+     * Define a class using the module of an existing class.
+     *
+     * @param originalClass the existing class (must not be {@code null})
+     * @param className the new class name (must not be {@code null})
+     * @param protectionDomain the protection domain of the new class (must not be {@code null})
+     * @param classBytes the new class bytes (must not be {@code null})
+     * @param off the offset into the {@code classBytes} array
+     * @param len the number of bytes to use from the {@code classBytes} array
+     * @return the defined class (not {@code null})
+     */
+    public Class<?> defineClass(Class<?> originalClass, String className, ProtectionDomain protectionDomain, byte[] classBytes, int off, int len) {
+        final Module module = Module.forClass(originalClass);
+        if (module == null) throw new IllegalArgumentException("Original " + originalClass + " does not have a module");
+        return module.getClassLoaderPrivate().defineClassInternal(className, classBytes, off, len, protectionDomain);
+    }
+
+    /**
+     * Define a class using the module of an existing class.
+     *
+     * @param originalClass the existing class (must not be {@code null})
+     * @param className the new class name (must not be {@code null})
+     * @param protectionDomain the protection domain of the new class (must not be {@code null})
+     * @param classBytes the new class bytes (must not be {@code null})
+     * @return the defined class (not {@code null})
+     */
+    public Class<?> defineClass(Class<?> originalClass, String className, ProtectionDomain protectionDomain, byte[] classBytes) {
+        return defineClass(originalClass, className, protectionDomain, classBytes, 0, classBytes.length);
+    }
+
+    /**
+     * Define a class.
+     *
+     * @param module the module to define the class to (must not be {@code null})
+     * @param className the new class name (must not be {@code null})
+     * @param protectionDomain the protection domain of the new class (must not be {@code null})
+     * @param classBytes the new class bytes (must not be {@code null})
+     * @return the defined class (not {@code null})
+     */
+    public Class<?> defineClass(Module module, String className, ProtectionDomain protectionDomain, ByteBuffer classBytes) {
+        return module.getClassLoaderPrivate().defineClassInternal(className, classBytes, protectionDomain);
+    }
+
+    /**
+     * Define a class.
+     *
+     * @param module the module to define the class to (must not be {@code null})
+     * @param className the new class name (must not be {@code null})
+     * @param protectionDomain the protection domain of the new class (must not be {@code null})
+     * @param classBytes the new class bytes (must not be {@code null})
+     * @param off the offset into the {@code classBytes} array
+     * @param len the number of bytes to use from the {@code classBytes} array
+     * @return the defined class (not {@code null})
+     */
+    public Class<?> defineClass(Module module, String className, ProtectionDomain protectionDomain, byte[] classBytes, int off, int len) {
+        return module.getClassLoaderPrivate().defineClassInternal(className, classBytes, off, len, protectionDomain);
+    }
+
+    /**
+     * Define a class.
+     *
+     * @param module the module to define the class to (must not be {@code null})
+     * @param className the new class name (must not be {@code null})
+     * @param protectionDomain the protection domain of the new class (must not be {@code null})
+     * @param classBytes the new class bytes (must not be {@code null})
+     * @return the defined class (not {@code null})
+     */
+    public Class<?> defineClass(Module module, String className, ProtectionDomain protectionDomain, byte[] classBytes) {
+        return defineClass(module, className, protectionDomain, classBytes, 0, classBytes.length);
+    }
+
+    /**
+     * Get the class definer instance.  The caller must have the {@code createClassLoader} {@link RuntimePermission}.
+     *
+     * @return the singleton class definer instance (not {@code null})
+     */
+    public static ClassDefiner getInstance() {
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(createClassLoaderPermission);
+        }
+        return instance;
+    }
+
+    private ProtectionDomain getProtectionDomain(final Class<?> clazz) {
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            return doPrivileged((PrivilegedAction<ProtectionDomain>) clazz::getProtectionDomain);
+        } else {
+            return clazz.getProtectionDomain();
+        }
+    }
+}


=====================================
src/main/java/org/jboss/modules/ModuleClassLoader.java
=====================================
@@ -449,6 +449,42 @@ public class ModuleClassLoader extends ConcurrentClassLoader {
         }
     }
 
+    Class<?> defineClassInternal(final String className, ByteBuffer byteBuffer, final ProtectionDomain protectionDomain) {
+        if (transformer != null) {
+            int pos = byteBuffer.position();
+            int lim = byteBuffer.limit();
+            ByteBuffer transformed;
+            try {
+                transformed = transformer.transform(this, className.replace('.', '/'), protectionDomain, byteBuffer);
+            } catch (Exception e) {
+                ClassFormatError error = new ClassFormatError(e.getMessage());
+                error.initCause(e);
+                throw error;
+            }
+            if (transformed != null) {
+                byteBuffer = transformed;
+            } else {
+                byteBuffer.position(0);
+                byteBuffer.limit(lim);
+                byteBuffer.position(pos);
+            }
+        }
+        final long start = Metrics.getCurrentCPUTime();
+        final Class<?> defined = defineClass(className, byteBuffer, protectionDomain);
+        module.getModuleLoader().addClassLoadTime(Metrics.getCurrentCPUTime() - start);
+        return defined;
+    }
+
+    Class<?> defineClassInternal(final String className, byte[] bytes, int off, int len, final ProtectionDomain protectionDomain) {
+        if (transformer != null) {
+            return defineClassInternal(className, ByteBuffer.wrap(bytes, off, len), protectionDomain);
+        }
+        final long start = Metrics.getCurrentCPUTime();
+        final Class<?> defined = defineClass(className, bytes, off, len, protectionDomain);
+        module.getModuleLoader().addClassLoadTime(Metrics.getCurrentCPUTime() - start);
+        return defined;
+    }
+
     /**
      * Define a class from a class name and class spec.  Also defines any enclosing {@link Package} instances,
      * and performs any sealed-package checks.


=====================================
src/main/java/org/jboss/modules/xml/ModuleXmlParser.java
=====================================
@@ -108,6 +108,13 @@ public final class ModuleXmlParser {
         }
     }
 
+    /**
+     * XML parsing callback for property elements.
+     */
+    private interface PropertiesCallback {
+        void parsedProperty(String name, String value);
+    }
+
     private ModuleXmlParser() {
     }
 
@@ -120,6 +127,7 @@ public final class ModuleXmlParser {
     private static final String MODULE_1_6 = "urn:jboss:module:1.6";
     private static final String MODULE_1_7 = "urn:jboss:module:1.7";
     private static final String MODULE_1_8 = "urn:jboss:module:1.8";
+    private static final String MODULE_1_9 = "urn:jboss:module:1.9";
 
     private static final String E_MODULE = "module";
     private static final String E_ARTIFACT = "artifact";
@@ -175,6 +183,24 @@ public final class ModuleXmlParser {
     private static final List<String> LIST_A_NAME_A_TARGET_NAME = Arrays.asList(A_NAME, A_TARGET_NAME);
     private static final List<String> LIST_A_PERMISSION_A_NAME = Arrays.asList(A_PERMISSION, A_NAME);
 
+    private static PropertiesCallback NOOP_PROPS_CALLBACK;
+
+    /**
+     * Returns a no-op implementation of properties callback currently used for
+     * parsing properties attached to module dependencies that aren't used at
+     * runtime in jboss-modules but are important in other projects where
+     * module dependencies are analyzed.
+     *
+     * @return  a no-op implementation of properties callback
+     */
+    private static PropertiesCallback getNoopPropsCallback() {
+        return NOOP_PROPS_CALLBACK == null ? NOOP_PROPS_CALLBACK = new PropertiesCallback() {
+            @Override
+            public void parsedProperty(String name, String value) {
+            }
+        } : NOOP_PROPS_CALLBACK;
+    }
+
     /**
      * Parse a {@code module.xml} file.
      *
@@ -394,6 +420,7 @@ public final class ModuleXmlParser {
             case MODULE_1_6:
             case MODULE_1_7:
             case MODULE_1_8:
+            case MODULE_1_9:
                 break;
             default: throw unexpectedContent(reader);
         }
@@ -408,7 +435,11 @@ public final class ModuleXmlParser {
     }
 
     private static boolean atLeast1_8(final XmlPullParser reader) {
-        return MODULE_1_8.equals(reader.getNamespace());
+        return MODULE_1_8.equals(reader.getNamespace()) || atLeast1_9(reader);
+    }
+
+    private static boolean atLeast1_9(final XmlPullParser reader) {
+        return MODULE_1_9.equals(reader.getNamespace());
     }
 
     private static void assertNoAttributes(final XmlPullParser reader) throws XmlPullParserException {
@@ -677,7 +708,15 @@ public final class ModuleXmlParser {
                         case E_DEPENDENCIES: parseDependencies(reader, dependencies); break;
                         case E_MAIN_CLASS:   parseMainClass(reader, specBuilder); break;
                         case E_RESOURCES:    parseResources(mavenResolver, factory, rootPath, reader, specBuilder); break;
-                        case E_PROPERTIES:   parseProperties(reader, specBuilder); break;
+                        case E_PROPERTIES:   parseProperties(reader, new PropertiesCallback() {
+                            @Override
+                            public void parsedProperty(String name, String value) {
+                                specBuilder.addProperty(name, value);
+                                if ("jboss.assertions".equals(name)) try {
+                                    specBuilder.setAssertionSetting(AssertionSetting.valueOf(value.toUpperCase(Locale.US)));
+                                } catch (IllegalArgumentException ignored) {}
+                            }
+                        }); break;
                         case E_PERMISSIONS:  parsePermissions(reader, moduleLoader, realModuleName, specBuilder); gotPerms = true; break;
                         case E_PROVIDES:     if (is1_8) parseProvidesType(reader, specBuilder); else throw unexpectedContent(reader); break;
                         default: throw unexpectedContent(reader);
@@ -794,6 +833,7 @@ public final class ModuleXmlParser {
                     switch (reader.getName()) {
                         case E_EXPORTS: parseFilterList(reader, exportBuilder); break;
                         case E_IMPORTS: parseFilterList(reader, importBuilder); break;
+                        case E_PROPERTIES: if (atLeast1_9(reader)) { parseProperties(reader, getNoopPropsCallback()); break; }
                         default: throw unexpectedContent(reader);
                     }
                     break;
@@ -1019,9 +1059,6 @@ public final class ModuleXmlParser {
                         try {
                             coordinates = ArtifactCoordinates.fromString(name);
                             final File file = mavenResolver.resolveJarArtifact(coordinates);
-                            if (file == null) {
-                                throw new XmlPullParserException(String.format("Failed to resolve artifact '%s'", coordinates), reader, null);
-                            }
                             resourceLoader = factory.createResourceLoader("", file.getPath(), name);
                         } catch (IOException | IllegalArgumentException e) {
                             throw new XmlPullParserException(String.format("Failed to add artifact '%s'", name), reader, e);
@@ -1281,7 +1318,7 @@ public final class ModuleXmlParser {
         parseNoContent(reader);
     }
 
-    private static void parseProperties(final XmlPullParser reader, final ModuleSpec.Builder specBuilder) throws XmlPullParserException, IOException {
+    private static void parseProperties(final XmlPullParser reader, final PropertiesCallback propsCallback) throws XmlPullParserException, IOException {
         assertNoAttributes(reader);
         // xsd:choice
         int eventType;
@@ -1295,7 +1332,7 @@ public final class ModuleXmlParser {
                     validateNamespace(reader);
                     switch (reader.getName()) {
                         case E_PROPERTY: {
-                            parseProperty(reader, specBuilder);
+                            parseProperty(reader, propsCallback);
                             break;
                         }
                         default: throw unexpectedContent(reader);
@@ -1309,7 +1346,7 @@ public final class ModuleXmlParser {
         }
     }
 
-    private static void parseProperty(final XmlPullParser reader, final ModuleSpec.Builder specBuilder) throws XmlPullParserException, IOException {
+    private static void parseProperty(final XmlPullParser reader, final PropertiesCallback propsCallback) throws XmlPullParserException, IOException {
         String name = null;
         String value = null;
         final Set<String> required = new HashSet<>(LIST_A_NAME);
@@ -1327,10 +1364,7 @@ public final class ModuleXmlParser {
         if (! required.isEmpty()) {
             throw missingAttributes(reader, required);
         }
-        specBuilder.addProperty(name, value == null ? "true" : value);
-        if ("jboss.assertions".equals(name)) try {
-            specBuilder.setAssertionSetting(AssertionSetting.valueOf(value.toUpperCase(Locale.US)));
-        } catch (IllegalArgumentException ignored) {}
+        propsCallback.parsedProperty(name, value == null ? "true" : value);
 
         // consume remainder of element
         parseNoContent(reader);


=====================================
src/main/resources/schema/module-1_9.xsd
=====================================
@@ -0,0 +1,651 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ JBoss, Home of Professional Open Source.
+  ~ Copyright 2018 Red Hat, Inc., and individual contributors
+  ~ as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+            targetNamespace="urn:jboss:module:1.9"
+            xmlns="urn:jboss:module:1.9"
+            elementFormDefault="qualified"
+            version="1.0">
+
+    <!-- Root element -->
+    <xsd:element name="module" type="moduleType">
+        <xsd:annotation>
+            <xsd:documentation>
+                Root element for a module declaration.
+            </xsd:documentation>
+        </xsd:annotation>
+    </xsd:element>
+
+    <!-- Root element -->
+    <xsd:element name="module-alias" type="moduleAliasType">
+        <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+            <documentation>
+                Root element for a module alias declaration.
+            </documentation>
+        </annotation>
+    </xsd:element>
+
+    <!-- Root element -->
+    <xsd:element name="module-absent" type="moduleAbsentType">
+        <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+            <documentation>
+                Root element for an absent module.
+            </documentation>
+        </annotation>
+    </xsd:element>
+
+    <xsd:complexType name="moduleType">
+        <xsd:annotation>
+            <xsd:documentation>
+                The module declaration type; contains dependencies, resources, and the main class
+                specification.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:all>
+            <xsd:element name="exports" type="filterType" minOccurs="0">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        Lists filter expressions to apply to the export filter of the local resources of this module
+                        (optional). By default, everything is exported. If filter expressions are provided, the default
+                        action is to accept all paths if no filters match.
+                    </documentation>
+                </annotation>
+            </xsd:element>
+            <xsd:element name="dependencies" type="dependenciesType" minOccurs="0">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        Lists the dependencies of this module (optional).
+                    </documentation>
+                </annotation>
+            </xsd:element>
+            <xsd:element name="resources" type="resourcesType" minOccurs="0">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        Lists the resource roots of this module (optional).
+                    </documentation>
+                </annotation>
+            </xsd:element>
+            <xsd:element name="main-class" type="classNameType" minOccurs="0">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        Specifies the main class of this module; used to run the module from the command-line
+                        (optional).
+                    </documentation>
+                </annotation>
+            </xsd:element>
+            <xsd:element name="properties" type="propertyListType" minOccurs="0">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        Lists the user-defined properties to be associated with this module (optional).
+                    </documentation>
+                </annotation>
+            </xsd:element>
+            <xsd:element name="permissions" type="permissionsType" minOccurs="0">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        Lists the requested permission set for this module. If the requested permissions cannot
+                        be assigned, the module cannot be loaded.
+                    </documentation>
+                </annotation>
+            </xsd:element>
+            <xsd:element name="provides" type="providesType" minOccurs="0">
+                <xsd:annotation>
+                    <xsd:documentation>
+                        Lists items that are statically provided by this module.
+                    </xsd:documentation>
+                </xsd:annotation>
+            </xsd:element>
+        </xsd:all>
+        <xsd:attribute name="name" type="xsd:string" use="required">
+            <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                <documentation>
+                    The name of this module (required).
+                </documentation>
+            </annotation>
+        </xsd:attribute>
+        <xsd:attribute name="version" type="moduleVersionType">
+            <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                <documentation>
+                    The version of this module (optional).
+                </documentation>
+            </annotation>
+        </xsd:attribute>
+    </xsd:complexType>
+
+    <xsd:simpleType name="moduleVersionType">
+        <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+            <documentation>
+                A module version string.
+            </documentation>
+        </annotation>
+        <xsd:restriction base="xsd:string">
+            <xsd:pattern value="([a-zA-Z0-9]+)([-_+.][a-zA-Z0-9]+)*"/>
+        </xsd:restriction>
+    </xsd:simpleType>
+
+    <xsd:complexType name="dependenciesType">
+        <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+            <documentation>
+                A list of zero or more module dependencies.
+            </documentation>
+        </annotation>
+        <xsd:choice minOccurs="0" maxOccurs="unbounded">
+            <xsd:element name="module" type="moduleDependencyType">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        A specified module dependency.
+                    </documentation>
+                </annotation>
+            </xsd:element>
+       </xsd:choice>
+    </xsd:complexType>
+
+    <xsd:complexType name="moduleDependencyType">
+        <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+            <documentation>
+                A single module dependency expression.
+            </documentation>
+        </annotation>
+        <xsd:all minOccurs="0">
+            <xsd:element name="properties" type="propertyListType" minOccurs="0">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        Lists the user-defined properties to be associated with this module dependency (optional).
+                    </documentation>
+                </annotation>
+            </xsd:element>
+            <xsd:element name="exports" type="filterType" minOccurs="0">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        A filter used to restrict what packages or directories from this dependency are re-exported by
+                        this module. See also the "export" and "services" attributes. The default action of this filter
+                        list is controlled by the value of the "export" attribute. Regardless of the setting of these
+                        attributes, this filter always behaves as if it has a final entry which rejects META-INF and
+                        all of its subdirectories.
+                    </documentation>
+                </annotation>
+            </xsd:element>
+            <xsd:element name="imports" type="filterType" minOccurs="0">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        A filter used to restrict what packages or directories from this dependency are visible to this
+                        module. See also the "services" attribute. The default action of this filter list is to reject
+                        a path if not matched.
+                    </documentation>
+                </annotation>
+            </xsd:element>
+        </xsd:all>
+        <xsd:attribute name="name" type="xsd:string" use="required">
+            <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                <documentation>
+                    The dependency module name (required).
+                </documentation>
+            </annotation>
+        </xsd:attribute>
+        <xsd:attribute name="export" type="xsd:boolean" default="false">
+            <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                <documentation>
+                    Specifies whether this module dependency is re-exported by default (default is "false"). Setting
+                    this attribute to true sets the default action for the export filter list to "accept"; leaving it
+                    as false sets the default action to "reject".  Thus you can still export dependency resources even
+                    if this attribute is false by listing explicit paths for the export list.
+                </documentation>
+            </annotation>
+        </xsd:attribute>
+        <xsd:attribute name="services" type="serviceDispositionType" default="none">
+            <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                <documentation>
+                    Specifies whether and how services found in this dependency are used (default is "none"). Specifying
+                    a value of "import" for this attribute is equivalent to adding a filter at the end of the import
+                    filter list which includes the META-INF/services path from the dependency module.  Setting a value
+                    of "export" for this attribute is equivalent to the same action on the export filter list.
+                </documentation>
+            </annotation>
+        </xsd:attribute>
+        <xsd:attribute name="optional" type="xsd:boolean" default="false">
+            <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                <documentation>
+                    Specifies whether this dependency is optional (defaults to false). An optional dependency will not
+                    cause the module to fail to load if not found; however if the module is added later, it will not be
+                    retroactively linked into this module's dependency list.
+                </documentation>
+            </annotation>
+        </xsd:attribute>
+    </xsd:complexType>
+
+    <xsd:simpleType name="serviceDispositionType">
+        <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+            <documentation>
+                The requested behavior for service handling on a dependency.
+            </documentation>
+        </annotation>
+        <xsd:restriction base="xsd:string">
+            <xsd:enumeration value="none">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        Do not import or export services from this dependency.
+                    </documentation>
+                </annotation>
+            </xsd:enumeration>
+            <xsd:enumeration value="import">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        Import, but do not re-export, services from this dependency.
+                    </documentation>
+                </annotation>
+            </xsd:enumeration>
+            <xsd:enumeration value="export">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        Import and re-export services found in this dependency.
+                    </documentation>
+                </annotation>
+            </xsd:enumeration>
+        </xsd:restriction>
+    </xsd:simpleType>
+
+    <xsd:complexType name="classNameType">
+        <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+            <documentation>
+                A class name.
+            </documentation>
+        </annotation>
+        <xsd:attribute name="name" type="xsd:string" use="required">
+            <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                <documentation>
+                    The class name.
+                </documentation>
+            </annotation>
+        </xsd:attribute>
+    </xsd:complexType>
+
+    <xsd:complexType name="pathType">
+        <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+            <documentation>
+                A filesystem path name.
+            </documentation>
+        </annotation>
+        <xsd:attribute name="name" type="xsd:string" use="required">
+            <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                <documentation>
+                    The path name.
+                </documentation>
+            </annotation>
+        </xsd:attribute>
+    </xsd:complexType>
+
+    <xsd:complexType name="resourcesType">
+        <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+            <documentation>
+                A list of zero or more resource roots for this deployment.
+            </documentation>
+        </annotation>
+        <xsd:choice minOccurs="0" maxOccurs="unbounded">
+            <xsd:element name="resource-root" type="resourceType">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        A resource root within this deployment.
+                    </documentation>
+                </annotation>
+            </xsd:element>
+            <xsd:element name="artifact" type="artifactType">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        A maven artifact within this deployment.
+                    </documentation>
+                </annotation>
+            </xsd:element>
+            <xsd:element name="native-artifact" type="artifactType">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        A maven native artifact within this deployment.  This is a jar that contains a lib/ directory
+                        with corresponding platform directories and binaries.  This element will cause the jar to
+                        be unzipped within the artifact's local repository directory.
+                    </documentation>
+                </annotation>
+            </xsd:element>
+        </xsd:choice>
+    </xsd:complexType>
+
+    <xsd:complexType name="artifactType">
+        <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+            <documentation>
+                A maven artifact within a deployment.
+            </documentation>
+        </annotation>
+        <xsd:all>
+            <xsd:element name="filter" type="filterType" minOccurs="0">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        A path filter specification for this resource root (optional). By default all paths are accepted.
+                    </documentation>
+                </annotation>
+            </xsd:element>
+            <xsd:element name="conditions" type="conditionsType" minOccurs="0">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        A condition filter specification for this resource root (optional). If this resolves to false the resource will not be used.
+                    </documentation>
+                </annotation>
+            </xsd:element>
+        </xsd:all>
+        <xsd:attribute name="name" type="xsd:string" use="required">
+            <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                <documentation>
+                    URI that points to the maven artifact "group:artifact:version[:classifier]"
+                </documentation>
+            </annotation>
+        </xsd:attribute>
+    </xsd:complexType>
+
+
+    <xsd:complexType name="resourceType">
+        <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+            <documentation>
+                A resource root within a deployment.
+            </documentation>
+        </annotation>
+        <xsd:all>
+            <xsd:element name="filter" type="filterType" minOccurs="0">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        A path filter specification for this resource root (optional). By default all paths are accepted.
+                    </documentation>
+                </annotation>
+            </xsd:element>
+            <xsd:element name="conditions" type="conditionsType" minOccurs="0">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        A condition filter specification for this resource root (optional). If this resolves to false the resource will not be used.
+                    </documentation>
+                </annotation>
+            </xsd:element>
+        </xsd:all>
+        <xsd:attribute name="path" type="xsd:string" use="required">
+            <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                <documentation>
+                    The path of this resource root, either absolute or relative.  Relative paths are resolved with respect to the location at which the module.xml file is found.
+                </documentation>
+            </annotation>
+        </xsd:attribute>
+    </xsd:complexType>
+
+    <xsd:complexType name="filterType">
+        <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+            <documentation>
+                A filter specification, consisting of zero or more filter items.
+            </documentation>
+        </annotation>
+        <xsd:choice minOccurs="0" maxOccurs="unbounded">
+            <xsd:element name="include" type="pathSpecType" minOccurs="0">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        A path to include. The path value can be a path name or a "glob" which may include the special
+                        wildcards "*", "**", and "?".
+                    </documentation>
+                </annotation>
+            </xsd:element>
+            <xsd:element name="exclude" type="pathSpecType" minOccurs="0">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        A path to exclude. The path value can be a path name or a "glob" which may include the special
+                        wildcards "*", "**", and "?".
+                    </documentation>
+                </annotation>
+            </xsd:element>
+            <xsd:element name="include-set" type="pathSetType" minOccurs="0">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        A set of literal path names to include. Wildcards are not supported.
+                    </documentation>
+                </annotation>
+            </xsd:element>
+            <xsd:element name="exclude-set" type="pathSetType" minOccurs="0">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        A set of literal path names to exclude. Wildcards are not supported.
+                    </documentation>
+                </annotation>
+            </xsd:element>
+        </xsd:choice>
+    </xsd:complexType>
+
+    <xsd:complexType name="pathSpecType">
+        <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+            <documentation>
+                A path specification type, which may include wildcards.
+            </documentation>
+        </annotation>
+        <xsd:attribute name="path" type="xsd:string" use="required">
+            <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                <documentation>
+                    The path name, which can be a literal path name or it may include the special wildcards "*", "**",
+                    and "?".
+                </documentation>
+            </annotation>
+        </xsd:attribute>
+    </xsd:complexType>
+
+    <xsd:complexType name="pathSetType">
+        <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+            <documentation>
+                A set of literal path names which can be used for efficient matching against multiple possible values.
+            </documentation>
+        </annotation>
+        <xsd:choice minOccurs="0" maxOccurs="unbounded">
+            <xsd:element name="path" type="pathType" minOccurs="0">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        The path name to include in the set.
+                    </documentation>
+                </annotation>
+            </xsd:element>
+        </xsd:choice>
+    </xsd:complexType>
+
+    <xsd:complexType name="moduleAliasType">
+        <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+            <documentation>
+                A module alias type, which defines the target for a module alias.
+            </documentation>
+        </annotation>
+        <xsd:attribute name="name" type="xsd:string" use="required">
+            <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                <documentation>
+                    The name of this module alias (required).
+                </documentation>
+            </annotation>
+        </xsd:attribute>
+        <xsd:attribute name="target-name" type="xsd:string" use="required">
+            <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                <documentation>
+                    The name of the module to which this alias refers (required).
+                </documentation>
+            </annotation>
+        </xsd:attribute>
+    </xsd:complexType>
+
+    <xsd:complexType name="moduleAbsentType">
+        <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+            <documentation>
+                An explicitly absent module.
+            </documentation>
+        </annotation>
+        <xsd:attribute name="name" type="xsd:string" use="required">
+            <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                <documentation>
+                    The name of the absent module (required).
+                </documentation>
+            </annotation>
+        </xsd:attribute>
+    </xsd:complexType>
+
+    <xsd:complexType name="propertyListType">
+        <xsd:choice minOccurs="0" maxOccurs="unbounded">
+            <xsd:element name="property" type="propertyType">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        A property in this property list.
+                    </documentation>
+                </annotation>
+            </xsd:element>
+        </xsd:choice>
+    </xsd:complexType>
+
+    <xsd:complexType name="propertyType">
+        <xsd:attribute name="name" type="xsd:string" use="required">
+            <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                <documentation>
+                    The property name as a string (required).
+                </documentation>
+            </annotation>
+        </xsd:attribute>
+        <xsd:attribute name="value" type="xsd:string" default="true">
+            <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                <documentation>
+                    The property value (optional, defaults to "true").
+                </documentation>
+            </annotation>
+        </xsd:attribute>
+    </xsd:complexType>
+
+    <xsd:complexType name="permissionsType">
+        <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+            <documentation>
+                A list of permissions that this module requires.
+            </documentation>
+        </annotation>
+        <xsd:choice minOccurs="0" maxOccurs="unbounded">
+            <xsd:element name="grant" type="permissionType">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        The permission to grant.
+                    </documentation>
+                </annotation>
+            </xsd:element>
+        </xsd:choice>
+    </xsd:complexType>
+    
+    <xsd:complexType name="permissionType">
+        <xsd:attribute name="permission" type="xsd:string" use="required">
+            <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                <documentation>
+                    The qualified class name of the permission to grant.
+                </documentation>
+            </annotation>
+        </xsd:attribute>
+        <xsd:attribute name="name" type="xsd:string">
+            <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                <documentation>
+                    The permission name to provide to the permission class constructor.
+                </documentation>
+            </annotation>
+        </xsd:attribute>
+        <xsd:attribute name="actions" type="xsd:string">
+            <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                <documentation>
+                    The (optional) list of actions, required by some permission types.
+                </documentation>
+            </annotation>
+        </xsd:attribute>
+    </xsd:complexType>
+
+    <xsd:complexType name="conditionsType">
+        <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+            <documentation>
+                A condition that determines if a resource is used. All conditions must resolve to true for the resource to be included in the module.
+            </documentation>
+        </annotation>
+        <xsd:sequence>
+            <xsd:element name="property-equal" type="propertyConditionType" minOccurs="0">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        A condition that evaluates to true if the property is equal to the provided value.
+                    </documentation>
+                </annotation>
+            </xsd:element>
+            <xsd:element name="property-not-equal" type="propertyConditionType" minOccurs="0">
+                <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+                    <documentation>
+                        A condition that evaluates to true if the property is equal to the provided value.
+                    </documentation>
+                </annotation>
+            </xsd:element>
+        </xsd:sequence>
+    </xsd:complexType>
+
+    <xsd:complexType name="propertyConditionType">
+        <annotation xmlns="http://www.w3.org/2001/XMLSchema">
+            <documentation>
+                A condition based on the value of a system property.
+            </documentation>
+        </annotation>
+        <xsd:attribute name="name" use="required">
+            <xsd:annotation>
+                <xsd:documentation>
+                    The property name
+                </xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
+        <xsd:attribute name="value" use="required">
+            <xsd:annotation>
+                <xsd:documentation>
+                    The property value
+                </xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
+    </xsd:complexType>
+
+    <xsd:complexType name="providesType">
+        <xsd:annotation>
+            <xsd:documentation>
+                The items that are provided by a module.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:choice minOccurs="0" maxOccurs="unbounded">
+            <xsd:element name="service" type="providedServiceType">
+                <xsd:annotation>
+                    <xsd:documentation>
+                        A service to provide.
+                    </xsd:documentation>
+                </xsd:annotation>
+            </xsd:element>
+        </xsd:choice>
+    </xsd:complexType>
+
+    <xsd:complexType name="providedServiceType">
+        <xsd:annotation>
+            <xsd:documentation>
+                A service that is provided by one or more implementations.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:choice minOccurs="0" maxOccurs="unbounded">
+            <xsd:element name="with-class" type="classNameType"/>
+        </xsd:choice>
+        <xsd:attribute name="name" type="xsd:string" use="required">
+            <xsd:annotation>
+                <xsd:documentation>
+                    The name of the service type.
+                </xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
+    </xsd:complexType>
+
+</xsd:schema>


=====================================
src/test/java/org/jboss/modules/ClassDefinerTest.java
=====================================
@@ -0,0 +1,99 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2018 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jboss.modules;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.CodeSigner;
+import java.security.CodeSource;
+import java.security.ProtectionDomain;
+import java.util.Collection;
+import java.util.Collections;
+import org.jboss.modules.util.TestModuleLoader;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ */
+public class ClassDefinerTest extends AbstractModuleTestCase {
+
+    private TestModuleLoader moduleLoader;
+
+    @Before
+    public void setupModuleLoader() {
+        moduleLoader = new TestModuleLoader();
+        ModuleSpec.Builder builder = ModuleSpec.build("org.module.foo");
+        builder.addDependency(ModuleDependencySpec.JAVA_BASE);
+        builder.addDependency(DependencySpec.OWN_DEPENDENCY);
+        builder.addResourceRoot(ResourceLoaderSpec.createResourceLoaderSpec(new ResourceLoader() {
+            public ClassSpec getClassSpec(final String fileName) {
+                return null;
+            }
+
+            public PackageSpec getPackageSpec(final String name) {
+                return null;
+            }
+
+            public Resource getResource(final String name) {
+                return null;
+            }
+
+            public String getLibrary(final String name) {
+                return null;
+            }
+
+            public Collection<String> getPaths() {
+                return Collections.singletonList("org/module/foo");
+            }
+        }));
+        moduleLoader.addModuleSpec(builder.create());
+    }
+
+    @Test
+    public void testDefineClass() throws ModuleLoadException, IOException, ClassNotFoundException {
+        final ClassDefiner classDefiner = ClassDefiner.getInstance();
+        final Module module = moduleLoader.loadModule("org.module.foo");
+        final URL resource = ClassDefinerTest.class.getClassLoader().getResource("test/GeneratedClass.class");
+        assertNotNull(resource);
+        final byte[] classBytes;
+        try (final InputStream stream = resource.openConnection().getInputStream()) {
+            try (final ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+                byte[] buf = new byte[256];
+                int res;
+                while ((res = stream.read(buf)) != -1) {
+                    os.write(buf, 0, res);
+                }
+                classBytes = os.toByteArray();
+            }
+        }
+        Class<?> c1 = classDefiner.defineClass(module, "org.module.foo.GeneratedClass", new ProtectionDomain(
+                new CodeSource(
+                        resource, (CodeSigner[]) null
+                ),
+                ModulesPolicy.DEFAULT_PERMISSION_COLLECTION
+        ), classBytes);
+        Class<?> c2 = module.getClassLoaderPrivate().loadClass("org.module.foo.GeneratedClass");
+        assertEquals(c1, c2);
+        assertEquals(module.getClassLoaderPrivate(), c1.getClassLoader());
+    }
+}


=====================================
src/test/java/org/jboss/modules/ModulePropertyTest.java
=====================================
@@ -24,6 +24,7 @@ import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
 
 /**
  * Test to verify the functionality of module properties.
@@ -47,4 +48,37 @@ public class ModulePropertyTest extends AbstractModuleTestCase {
         assertEquals("true", module.getProperty("test.prop.1"));
         assertEquals("propertyValue", module.getProperty("test.prop.2"));
     }
+
+    /**
+     * This test parses properties attached to module dependencies.
+     * The properties are currently not exposed via the dependency spec API,
+     * so the test simply makes sure they can be parsed w/o errors.
+     * @throws Exception
+     */
+    @Test
+    public void testModuleDependencyProperties() throws Exception {
+        Module module = moduleLoader.loadModule("test.dep-props");
+        assertNull(module.getProperty("non-existent"));
+        assertEquals("blah", module.getProperty("non-existent", "blah"));
+
+        final DependencySpec[] deps = module.getDependencies();
+        int testedDepsTotal = 0;
+        for(DependencySpec dep : deps) {
+            if(!(dep instanceof ModuleDependencySpec)) {
+                continue;
+            }
+            final ModuleDependencySpec moduleDep = (ModuleDependencySpec) dep;
+            String depName = moduleDep.getName();
+            if(!depName.startsWith("test.")) {
+                continue;
+            }
+            ++testedDepsTotal;
+            depName = depName.substring("test.".length());
+            if(depName.equals("test")) {
+            } else {
+                fail("Unexpected module dependency " + moduleDep);
+            }
+        }
+        assertEquals(1, testedDepsTotal);
+    }
 }


=====================================
src/test/resources/test/GeneratedClass.class
=====================================
Binary files /dev/null and b/src/test/resources/test/GeneratedClass.class differ


=====================================
src/test/resources/test/repo/test/dep-props/main/module.xml
=====================================
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ JBoss, Home of Professional Open Source.
+  ~ Copyright 2018 Red Hat, Inc., and individual contributors
+  ~ as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<module xmlns="urn:jboss:module:1.9" name="test.dep-props">
+
+    <resources/>
+
+    <dependencies>
+        <module name="test.test">
+            <properties>
+                <property name="test.dep.prop.1"/>
+                <property name="test.dep.prop.2" value="depPropertyValue"/>
+            </properties>
+        </module>
+    </dependencies>
+</module>



View it on GitLab: https://salsa.debian.org/java-team/jboss-modules/commit/11aee39db488c2fd7242ec6060c79484a9e79309

-- 
View it on GitLab: https://salsa.debian.org/java-team/jboss-modules/commit/11aee39db488c2fd7242ec6060c79484a9e79309
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20190121/4712f4d5/attachment.html>


More information about the pkg-java-commits mailing list