me.lucko.jarrelocator.JarRelocatorTask Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jar-relocator Show documentation
Show all versions of jar-relocator Show documentation
Utility to relocate classes within Jar archives
/*
* Copyright Apache Software Foundation
*
* 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 me.lucko.jarrelocator;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.jar.*;
import java.util.regex.Pattern;
/**
* A task that copies {@link JarEntry jar entries} from a {@link JarFile jar input} to a
* {@link JarOutputStream jar output}, applying the relocations defined by a
* {@link RelocatingRemapper}.
*/
final class JarRelocatorTask {
/**
* META-INF/*.SF
* META-INF/*.DSA
* META-INF/*.RSA
* META-INF/SIG-*
*
* Specification
*/
private static final Pattern SIGNATURE_FILE_PATTERN = Pattern.compile("META-INF/(?:[^/]+\\.(?:DSA|RSA|SF)|SIG-[^/]+)");
/**
* Specification
*/
private static final Pattern SIGNATURE_PROPERTY_PATTERN = Pattern.compile(".*-Digest");
private final RelocatingRemapper remapper;
private final JarOutputStream jarOut;
private final JarFile jarIn;
private final Set resources = new HashSet<>();
JarRelocatorTask(RelocatingRemapper remapper, JarOutputStream jarOut, JarFile jarIn) {
this.remapper = remapper;
this.jarOut = jarOut;
this.jarIn = jarIn;
}
void processEntries() throws IOException {
for (Enumeration entries = this.jarIn.entries(); entries.hasMoreElements(); ) {
JarEntry entry = entries.nextElement();
// The 'INDEX.LIST' file is an optional file, containing information about the packages
// defined in a jar. Instead of relocating the entries in it, we delete it, since it is
// optional anyway.
//
// We don't process directory entries, and instead opt to recreate them when adding
// classes/resources.
String name = entry.getName();
if (name.equals("META-INF/INDEX.LIST") || entry.isDirectory()) {
continue;
}
// Signatures will become invalid after remapping, so we delete them to avoid making the output useless
if (SIGNATURE_FILE_PATTERN.matcher(name).matches()) {
continue;
}
try (InputStream entryIn = this.jarIn.getInputStream(entry)) {
processEntry(entry, entryIn);
}
}
}
private void processEntry(JarEntry entry, InputStream entryIn) throws IOException {
String name = entry.getName();
String mappedName = this.remapper.map(name);
// ensure the parent directory structure exists for the entry.
processDirectory(mappedName, true);
if (name.endsWith(".class")) {
processClass(name, entryIn);
} else if (name.equals("META-INF/MANIFEST.MF")) {
processManifest(name, entryIn, entry.getTime());
} else if (!this.resources.contains(mappedName)) {
processResource(mappedName, entryIn, entry.getTime());
}
}
private void processDirectory(String name, boolean parentsOnly) throws IOException {
int index = name.lastIndexOf('/');
if (index != -1) {
String parentDirectory = name.substring(0, index);
if (!this.resources.contains(parentDirectory)) {
processDirectory(parentDirectory, false);
}
}
if (parentsOnly) {
return;
}
// directory entries must end in "/"
JarEntry entry = new JarEntry(name + "/");
this.jarOut.putNextEntry(entry);
this.resources.add(name);
}
private void processManifest(String name, InputStream entryIn, long lastModified) throws IOException {
Manifest in = new Manifest(entryIn);
Manifest out = new Manifest();
out.getMainAttributes().putAll(in.getMainAttributes());
for (Map.Entry entry : in.getEntries().entrySet()) {
Attributes outAttributes = new Attributes();
for (Map.Entry
© 2015 - 2025 Weber Informatics LLC | Privacy Policy