Search in sources :

Example 1 with Builder

use of java.lang.module.ModuleDescriptor.Builder in project Bytecoder by mirkosertic.

the class ModuleInfo method readModuleAttribute.

/**
 * Reads the Module attribute, returning the ModuleDescriptor.Builder to
 * build the corresponding ModuleDescriptor.
 */
private Builder readModuleAttribute(DataInput in, ConstantPool cpool) throws IOException {
    // module_name
    int module_name_index = in.readUnsignedShort();
    String mn = cpool.getModuleName(module_name_index);
    int module_flags = in.readUnsignedShort();
    Set<ModuleDescriptor.Modifier> modifiers = new HashSet<>();
    boolean open = ((module_flags & ACC_OPEN) != 0);
    if (open)
        modifiers.add(ModuleDescriptor.Modifier.OPEN);
    if ((module_flags & ACC_SYNTHETIC) != 0)
        modifiers.add(ModuleDescriptor.Modifier.SYNTHETIC);
    if ((module_flags & ACC_MANDATED) != 0)
        modifiers.add(ModuleDescriptor.Modifier.MANDATED);
    Builder builder = JLMA.newModuleBuilder(mn, false, modifiers);
    int module_version_index = in.readUnsignedShort();
    if (module_version_index != 0) {
        String vs = cpool.getUtf8(module_version_index);
        builder.version(vs);
    }
    int requires_count = in.readUnsignedShort();
    boolean requiresJavaBase = false;
    for (int i = 0; i < requires_count; i++) {
        int requires_index = in.readUnsignedShort();
        String dn = cpool.getModuleName(requires_index);
        int requires_flags = in.readUnsignedShort();
        Set<Requires.Modifier> mods;
        if (requires_flags == 0) {
            mods = Collections.emptySet();
        } else {
            mods = new HashSet<>();
            if ((requires_flags & ACC_TRANSITIVE) != 0)
                mods.add(Requires.Modifier.TRANSITIVE);
            if ((requires_flags & ACC_STATIC_PHASE) != 0)
                mods.add(Requires.Modifier.STATIC);
            if ((requires_flags & ACC_SYNTHETIC) != 0)
                mods.add(Requires.Modifier.SYNTHETIC);
            if ((requires_flags & ACC_MANDATED) != 0)
                mods.add(Requires.Modifier.MANDATED);
        }
        int requires_version_index = in.readUnsignedShort();
        if (requires_version_index == 0) {
            builder.requires(mods, dn);
        } else {
            String vs = cpool.getUtf8(requires_version_index);
            JLMA.requires(builder, mods, dn, vs);
        }
        if (dn.equals("java.base"))
            requiresJavaBase = true;
    }
    if (mn.equals("java.base")) {
        if (requires_count > 0) {
            throw invalidModuleDescriptor("The requires table for java.base" + " must be 0 length");
        }
    } else if (!requiresJavaBase) {
        throw invalidModuleDescriptor("The requires table must have" + " an entry for java.base");
    }
    int exports_count = in.readUnsignedShort();
    if (exports_count > 0) {
        for (int i = 0; i < exports_count; i++) {
            int exports_index = in.readUnsignedShort();
            String pkg = cpool.getPackageName(exports_index);
            Set<Exports.Modifier> mods;
            int exports_flags = in.readUnsignedShort();
            if (exports_flags == 0) {
                mods = Collections.emptySet();
            } else {
                mods = new HashSet<>();
                if ((exports_flags & ACC_SYNTHETIC) != 0)
                    mods.add(Exports.Modifier.SYNTHETIC);
                if ((exports_flags & ACC_MANDATED) != 0)
                    mods.add(Exports.Modifier.MANDATED);
            }
            int exports_to_count = in.readUnsignedShort();
            if (exports_to_count > 0) {
                Set<String> targets = new HashSet<>(exports_to_count);
                for (int j = 0; j < exports_to_count; j++) {
                    int exports_to_index = in.readUnsignedShort();
                    String target = cpool.getModuleName(exports_to_index);
                    if (!targets.add(target)) {
                        throw invalidModuleDescriptor(pkg + " exported to " + target + " more than once");
                    }
                }
                builder.exports(mods, pkg, targets);
            } else {
                builder.exports(mods, pkg);
            }
        }
    }
    int opens_count = in.readUnsignedShort();
    if (opens_count > 0) {
        if (open) {
            throw invalidModuleDescriptor("The opens table for an open" + " module must be 0 length");
        }
        for (int i = 0; i < opens_count; i++) {
            int opens_index = in.readUnsignedShort();
            String pkg = cpool.getPackageName(opens_index);
            Set<Opens.Modifier> mods;
            int opens_flags = in.readUnsignedShort();
            if (opens_flags == 0) {
                mods = Collections.emptySet();
            } else {
                mods = new HashSet<>();
                if ((opens_flags & ACC_SYNTHETIC) != 0)
                    mods.add(Opens.Modifier.SYNTHETIC);
                if ((opens_flags & ACC_MANDATED) != 0)
                    mods.add(Opens.Modifier.MANDATED);
            }
            int open_to_count = in.readUnsignedShort();
            if (open_to_count > 0) {
                Set<String> targets = new HashSet<>(open_to_count);
                for (int j = 0; j < open_to_count; j++) {
                    int opens_to_index = in.readUnsignedShort();
                    String target = cpool.getModuleName(opens_to_index);
                    if (!targets.add(target)) {
                        throw invalidModuleDescriptor(pkg + " opened to " + target + " more than once");
                    }
                }
                builder.opens(mods, pkg, targets);
            } else {
                builder.opens(mods, pkg);
            }
        }
    }
    int uses_count = in.readUnsignedShort();
    if (uses_count > 0) {
        for (int i = 0; i < uses_count; i++) {
            int index = in.readUnsignedShort();
            String sn = cpool.getClassName(index);
            builder.uses(sn);
        }
    }
    int provides_count = in.readUnsignedShort();
    if (provides_count > 0) {
        for (int i = 0; i < provides_count; i++) {
            int index = in.readUnsignedShort();
            String sn = cpool.getClassName(index);
            int with_count = in.readUnsignedShort();
            List<String> providers = new ArrayList<>(with_count);
            for (int j = 0; j < with_count; j++) {
                index = in.readUnsignedShort();
                String pn = cpool.getClassName(index);
                if (!providers.add(pn)) {
                    throw invalidModuleDescriptor(sn + " provides " + pn + " more than once");
                }
            }
            builder.provides(sn, providers);
        }
    }
    return builder;
}
Also used : Builder(java.lang.module.ModuleDescriptor.Builder) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet)

Example 2 with Builder

use of java.lang.module.ModuleDescriptor.Builder in project Bytecoder by mirkosertic.

the class ModuleInfo method doRead.

/**
 * Reads the input as a module-info class file.
 *
 * @throws IOException
 * @throws InvalidModuleDescriptorException
 * @throws IllegalArgumentException if thrown by the ModuleDescriptor.Builder
 *         because an identifier is not a legal Java identifier, duplicate
 *         exports, and many other reasons
 */
private Attributes doRead(DataInput in) throws IOException {
    int magic = in.readInt();
    if (magic != 0xCAFEBABE)
        throw invalidModuleDescriptor("Bad magic number");
    int minor_version = in.readUnsignedShort();
    int major_version = in.readUnsignedShort();
    if (major_version < 53) {
        throw invalidModuleDescriptor("Must be >= 53.0");
    }
    ConstantPool cpool = new ConstantPool(in);
    int access_flags = in.readUnsignedShort();
    if (access_flags != ACC_MODULE)
        throw invalidModuleDescriptor("access_flags should be ACC_MODULE");
    int this_class = in.readUnsignedShort();
    String mn = cpool.getClassName(this_class);
    if (!"module-info".equals(mn))
        throw invalidModuleDescriptor("this_class should be module-info");
    int super_class = in.readUnsignedShort();
    if (super_class > 0)
        throw invalidModuleDescriptor("bad #super_class");
    int interfaces_count = in.readUnsignedShort();
    if (interfaces_count > 0)
        throw invalidModuleDescriptor("Bad #interfaces");
    int fields_count = in.readUnsignedShort();
    if (fields_count > 0)
        throw invalidModuleDescriptor("Bad #fields");
    int methods_count = in.readUnsignedShort();
    if (methods_count > 0)
        throw invalidModuleDescriptor("Bad #methods");
    int attributes_count = in.readUnsignedShort();
    // the names of the attributes found in the class file
    Set<String> attributes = new HashSet<>();
    Builder builder = null;
    Set<String> allPackages = null;
    String mainClass = null;
    ModuleTarget moduleTarget = null;
    ModuleHashes moduelHashes = null;
    ModuleResolution moduleResolution = null;
    for (int i = 0; i < attributes_count; i++) {
        int name_index = in.readUnsignedShort();
        String attribute_name = cpool.getUtf8(name_index);
        int length = in.readInt();
        boolean added = attributes.add(attribute_name);
        if (!added && isAttributeAtMostOnce(attribute_name)) {
            throw invalidModuleDescriptor("More than one " + attribute_name + " attribute");
        }
        switch(attribute_name) {
            case MODULE:
                builder = readModuleAttribute(in, cpool);
                break;
            case MODULE_PACKAGES:
                allPackages = readModulePackagesAttribute(in, cpool);
                break;
            case MODULE_MAIN_CLASS:
                mainClass = readModuleMainClassAttribute(in, cpool);
                break;
            case MODULE_TARGET:
                moduleTarget = readModuleTargetAttribute(in, cpool);
                break;
            case MODULE_HASHES:
                if (parseHashes) {
                    moduelHashes = readModuleHashesAttribute(in, cpool);
                } else {
                    in.skipBytes(length);
                }
                break;
            case MODULE_RESOLUTION:
                moduleResolution = readModuleResolution(in, cpool);
                break;
            default:
                if (isAttributeDisallowed(attribute_name)) {
                    throw invalidModuleDescriptor(attribute_name + " attribute not allowed");
                } else {
                    in.skipBytes(length);
                }
        }
    }
    // the Module attribute is required
    if (builder == null) {
        throw invalidModuleDescriptor(MODULE + " attribute not found");
    }
    // ModuleMainClass  attribute
    if (mainClass != null) {
        builder.mainClass(mainClass);
    }
    // If the ModulePackages attribute is not present then the packageFinder
    // is used to find the set of packages
    boolean usedPackageFinder = false;
    if (allPackages == null && packageFinder != null) {
        try {
            allPackages = packageFinder.get();
        } catch (UncheckedIOException x) {
            throw x.getCause();
        }
        usedPackageFinder = true;
    }
    if (allPackages != null) {
        Set<String> knownPackages = JLMA.packages(builder);
        if (!allPackages.containsAll(knownPackages)) {
            Set<String> missingPackages = new HashSet<>(knownPackages);
            missingPackages.removeAll(allPackages);
            assert !missingPackages.isEmpty();
            String missingPackage = missingPackages.iterator().next();
            String tail;
            if (usedPackageFinder) {
                tail = " not found in module";
            } else {
                tail = " missing from ModulePackages class file attribute";
            }
            throw invalidModuleDescriptor("Package " + missingPackage + tail);
        }
        builder.packages(allPackages);
    }
    ModuleDescriptor descriptor = builder.build();
    return new Attributes(descriptor, moduleTarget, moduelHashes, moduleResolution);
}
Also used : Builder(java.lang.module.ModuleDescriptor.Builder) UncheckedIOException(java.io.UncheckedIOException) ModuleDescriptor(java.lang.module.ModuleDescriptor) HashSet(java.util.HashSet)

Example 3 with Builder

use of java.lang.module.ModuleDescriptor.Builder in project Bytecoder by mirkosertic.

the class ModulePath method deriveModuleDescriptor.

/**
 * Treat the given JAR file as a module as follows:
 *
 * 1. The value of the Automatic-Module-Name attribute is the module name
 * 2. The version, and the module name when the  Automatic-Module-Name
 *    attribute is not present, is derived from the file ame of the JAR file
 * 3. All packages are derived from the .class files in the JAR file
 * 4. The contents of any META-INF/services configuration files are mapped
 *    to "provides" declarations
 * 5. The Main-Class attribute in the main attributes of the JAR manifest
 *    is mapped to the module descriptor mainClass if possible
 */
private ModuleDescriptor deriveModuleDescriptor(JarFile jf) throws IOException {
    // Read Automatic-Module-Name attribute if present
    Manifest man = jf.getManifest();
    Attributes attrs = null;
    String moduleName = null;
    if (man != null) {
        attrs = man.getMainAttributes();
        if (attrs != null) {
            moduleName = attrs.getValue(AUTOMATIC_MODULE_NAME);
        }
    }
    // Derive the version, and the module name if needed, from JAR file name
    String fn = jf.getName();
    int i = fn.lastIndexOf(File.separator);
    if (i != -1)
        fn = fn.substring(i + 1);
    // drop ".jar"
    String name = fn.substring(0, fn.length() - 4);
    String vs = null;
    // find first occurrence of -${NUMBER}. or -${NUMBER}$
    Matcher matcher = Patterns.DASH_VERSION.matcher(name);
    if (matcher.find()) {
        int start = matcher.start();
        // attempt to parse the tail as a version string
        try {
            String tail = name.substring(start + 1);
            ModuleDescriptor.Version.parse(tail);
            vs = tail;
        } catch (IllegalArgumentException ignore) {
        }
        name = name.substring(0, start);
    }
    // Create builder, using the name derived from file name when
    // Automatic-Module-Name not present
    Builder builder;
    if (moduleName != null) {
        try {
            builder = ModuleDescriptor.newAutomaticModule(moduleName);
        } catch (IllegalArgumentException e) {
            throw new FindException(AUTOMATIC_MODULE_NAME + ": " + e.getMessage());
        }
    } else {
        builder = ModuleDescriptor.newAutomaticModule(cleanModuleName(name));
    }
    // module version if present
    if (vs != null)
        builder.version(vs);
    // scan the names of the entries in the JAR file
    Map<Boolean, Set<String>> map = VersionedStream.stream(jf).filter(e -> !e.isDirectory()).map(JarEntry::getName).filter(e -> (e.endsWith(".class") ^ e.startsWith(SERVICES_PREFIX))).collect(Collectors.partitioningBy(e -> e.startsWith(SERVICES_PREFIX), Collectors.toSet()));
    Set<String> classFiles = map.get(Boolean.FALSE);
    Set<String> configFiles = map.get(Boolean.TRUE);
    // the packages containing class files
    Set<String> packages = classFiles.stream().map(this::toPackageName).flatMap(Optional::stream).distinct().collect(Collectors.toSet());
    // all packages are exported and open
    builder.packages(packages);
    // map names of service configuration files to service names
    Set<String> serviceNames = configFiles.stream().map(this::toServiceName).flatMap(Optional::stream).collect(Collectors.toSet());
    // parse each service configuration file
    for (String sn : serviceNames) {
        JarEntry entry = jf.getJarEntry(SERVICES_PREFIX + sn);
        List<String> providerClasses = new ArrayList<>();
        try (InputStream in = jf.getInputStream(entry)) {
            BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
            String cn;
            while ((cn = nextLine(reader)) != null) {
                if (cn.length() > 0) {
                    String pn = packageName(cn);
                    if (!packages.contains(pn)) {
                        String msg = "Provider class " + cn + " not in module";
                        throw new InvalidModuleDescriptorException(msg);
                    }
                    providerClasses.add(cn);
                }
            }
        }
        if (!providerClasses.isEmpty())
            builder.provides(sn, providerClasses);
    }
    // Main-Class attribute if it exists
    if (attrs != null) {
        String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
        if (mainClass != null) {
            mainClass = mainClass.replace("/", ".");
            if (Checks.isClassName(mainClass)) {
                String pn = packageName(mainClass);
                if (packages.contains(pn)) {
                    builder.mainClass(mainClass);
                }
            }
        }
    }
    return builder.build();
}
Also used : Builder(java.lang.module.ModuleDescriptor.Builder) Manifest(java.util.jar.Manifest) NoSuchFileException(java.nio.file.NoSuchFileException) BufferedInputStream(java.io.BufferedInputStream) VersionedStream(jdk.internal.util.jar.VersionedStream) ModuleDescriptor(java.lang.module.ModuleDescriptor) ModuleReference(java.lang.module.ModuleReference) HashMap(java.util.HashMap) JarFile(java.util.jar.JarFile) ArrayList(java.util.ArrayList) Section(jdk.internal.jmod.JmodFile.Section) DirectoryStream(java.nio.file.DirectoryStream) JarEntry(java.util.jar.JarEntry) Matcher(java.util.regex.Matcher) ModuleFinder(java.lang.module.ModuleFinder) Map(java.util.Map) ZipFile(java.util.zip.ZipFile) URI(java.net.URI) Path(java.nio.file.Path) FindException(java.lang.module.FindException) PerfCounter(jdk.internal.perf.PerfCounter) ZipException(java.util.zip.ZipException) Files(java.nio.file.Files) Set(java.util.Set) IOException(java.io.IOException) BasicFileAttributes(java.nio.file.attribute.BasicFileAttributes) InputStreamReader(java.io.InputStreamReader) Attributes(java.util.jar.Attributes) Collectors(java.util.stream.Collectors) File(java.io.File) UncheckedIOException(java.io.UncheckedIOException) Objects(java.util.Objects) List(java.util.List) JmodFile(jdk.internal.jmod.JmodFile) Paths(java.nio.file.Paths) InvalidModuleDescriptorException(java.lang.module.InvalidModuleDescriptorException) Optional(java.util.Optional) BufferedReader(java.io.BufferedReader) Pattern(java.util.regex.Pattern) Collections(java.util.Collections) InputStream(java.io.InputStream) Set(java.util.Set) Optional(java.util.Optional) InputStreamReader(java.io.InputStreamReader) Matcher(java.util.regex.Matcher) BufferedInputStream(java.io.BufferedInputStream) InputStream(java.io.InputStream) Builder(java.lang.module.ModuleDescriptor.Builder) BasicFileAttributes(java.nio.file.attribute.BasicFileAttributes) Attributes(java.util.jar.Attributes) ArrayList(java.util.ArrayList) Manifest(java.util.jar.Manifest) JarEntry(java.util.jar.JarEntry) InvalidModuleDescriptorException(java.lang.module.InvalidModuleDescriptorException) FindException(java.lang.module.FindException) BufferedReader(java.io.BufferedReader)

Example 4 with Builder

use of java.lang.module.ModuleDescriptor.Builder in project Bytecoder by mirkosertic.

the class ModulePatcher method patchIfNeeded.

/**
 * Returns a module reference that interposes on the given module if
 * needed. If there are no patches for the given module then the module
 * reference is simply returned. Otherwise the patches for the module
 * are scanned (to find any new packages) and a new module reference is
 * returned.
 *
 * @throws UncheckedIOException if an I/O error is detected
 */
public ModuleReference patchIfNeeded(ModuleReference mref) {
    // if there are no patches for the module then nothing to do
    ModuleDescriptor descriptor = mref.descriptor();
    String mn = descriptor.name();
    List<Path> paths = map.get(mn);
    if (paths == null)
        return mref;
    // Scan the JAR file or directory tree to get the set of packages.
    // For automatic modules then packages that do not contain class files
    // must be ignored.
    Set<String> packages = new HashSet<>();
    boolean isAutomatic = descriptor.isAutomatic();
    try {
        for (Path file : paths) {
            if (Files.isRegularFile(file)) {
                // is not supported by the boot class loader
                try (JarFile jf = new JarFile(file.toString())) {
                    jf.stream().filter(e -> !e.isDirectory() && (!isAutomatic || e.getName().endsWith(".class"))).map(e -> toPackageName(file, e)).filter(Checks::isPackageName).forEach(packages::add);
                }
            } else if (Files.isDirectory(file)) {
                // exploded directory without following sym links
                Path top = file;
                Files.find(top, Integer.MAX_VALUE, ((path, attrs) -> attrs.isRegularFile())).filter(path -> (!isAutomatic || path.toString().endsWith(".class")) && !isHidden(path)).map(path -> toPackageName(top, path)).filter(Checks::isPackageName).forEach(packages::add);
            }
        }
    } catch (IOException ioe) {
        throw new UncheckedIOException(ioe);
    }
    // if there are new packages then we need a new ModuleDescriptor
    packages.removeAll(descriptor.packages());
    if (!packages.isEmpty()) {
        Builder builder = JLMA.newModuleBuilder(descriptor.name(), /*strict*/
        false, descriptor.modifiers());
        if (!descriptor.isAutomatic()) {
            descriptor.requires().forEach(builder::requires);
            descriptor.exports().forEach(builder::exports);
            descriptor.opens().forEach(builder::opens);
            descriptor.uses().forEach(builder::uses);
        }
        descriptor.provides().forEach(builder::provides);
        descriptor.version().ifPresent(builder::version);
        descriptor.mainClass().ifPresent(builder::mainClass);
        // original + new packages
        builder.packages(descriptor.packages());
        builder.packages(packages);
        descriptor = builder.build();
    }
    // return a module reference to the patched module
    URI location = mref.location().orElse(null);
    ModuleTarget target = null;
    ModuleHashes recordedHashes = null;
    ModuleHashes.HashSupplier hasher = null;
    ModuleResolution mres = null;
    if (mref instanceof ModuleReferenceImpl) {
        ModuleReferenceImpl impl = (ModuleReferenceImpl) mref;
        target = impl.moduleTarget();
        recordedHashes = impl.recordedHashes();
        hasher = impl.hasher();
        mres = impl.moduleResolution();
    }
    return new ModuleReferenceImpl(descriptor, location, () -> new PatchedModuleReader(paths, mref), this, target, recordedHashes, hasher, mres);
}
Also used : Path(java.nio.file.Path) Builder(java.lang.module.ModuleDescriptor.Builder) Resource(jdk.internal.loader.Resource) URL(java.net.URL) ModuleDescriptor(java.lang.module.ModuleDescriptor) ModuleReference(java.lang.module.ModuleReference) HashMap(java.util.HashMap) JarFile(java.util.jar.JarFile) JavaLangModuleAccess(jdk.internal.misc.JavaLangModuleAccess) ModuleReader(java.lang.module.ModuleReader) ByteBuffer(java.nio.ByteBuffer) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) JarEntry(java.util.jar.JarEntry) Map(java.util.Map) URI(java.net.URI) Path(java.nio.file.Path) SharedSecrets(jdk.internal.misc.SharedSecrets) MalformedURLException(java.net.MalformedURLException) Files(java.nio.file.Files) Set(java.util.Set) IOException(java.io.IOException) Collectors(java.util.stream.Collectors) File(java.io.File) IOError(java.io.IOError) UncheckedIOException(java.io.UncheckedIOException) List(java.util.List) Stream(java.util.stream.Stream) Paths(java.nio.file.Paths) Closeable(java.io.Closeable) Optional(java.util.Optional) ParseUtil(sun.net.www.ParseUtil) Collections(java.util.Collections) InputStream(java.io.InputStream) Builder(java.lang.module.ModuleDescriptor.Builder) UncheckedIOException(java.io.UncheckedIOException) IOException(java.io.IOException) UncheckedIOException(java.io.UncheckedIOException) JarFile(java.util.jar.JarFile) URI(java.net.URI) ModuleDescriptor(java.lang.module.ModuleDescriptor) HashSet(java.util.HashSet)

Aggregations

Builder (java.lang.module.ModuleDescriptor.Builder)4 UncheckedIOException (java.io.UncheckedIOException)3 ModuleDescriptor (java.lang.module.ModuleDescriptor)3 ArrayList (java.util.ArrayList)3 HashSet (java.util.HashSet)3 File (java.io.File)2 IOException (java.io.IOException)2 InputStream (java.io.InputStream)2 ModuleReference (java.lang.module.ModuleReference)2 URI (java.net.URI)2 Files (java.nio.file.Files)2 Path (java.nio.file.Path)2 Paths (java.nio.file.Paths)2 Collections (java.util.Collections)2 HashMap (java.util.HashMap)2 List (java.util.List)2 Map (java.util.Map)2 Optional (java.util.Optional)2 Set (java.util.Set)2 JarEntry (java.util.jar.JarEntry)2