Skip to content

Instantly share code, notes, and snippets.

@gregw
Created September 16, 2017 06:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gregw/8f305e369d0b769e9c3fe791a0634b13 to your computer and use it in GitHub Desktop.
Save gregw/8f305e369d0b769e9c3fe791a0634b13 to your computer and use it in GitHub Desktop.
Alternate impl of VersionedJarFile that handles inner classes
package org.eclipse.jetty.util;
import java.util.Map;
import java.util.TreeMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Stream;
public class VersionedJarFile
{
private static final String META_INF_VERSIONS = "META-INF/versions/";
public static Stream<JarEntry> stream(JarFile jf)
{
if (!jf.isMultiRelease())
return jf.stream();
// Map to hold unversioned name to VersionedJarEntry
Map<String,VersionedJarEntry> entries = new TreeMap<>();
// Fill the map, removing non applicable entries and replacing versions with later versions.
jf.stream()
.map(VersionedJarEntry::new)
.filter(e->e.isApplicable(jf.getVersion().major()))
.forEach(e->entries.compute(e.name, (k, v) -> v==null || v.isReplacedBy(e) ? e : v));
// filter the values to remove non applicable inner classes and map to versioned entry
return entries.values().stream()
.filter(e-> {
if (!e.inner)
return true;
VersionedJarEntry outer = entries.get(e.outer);
return outer != null && outer.version == e.version;
})
.map(e->e.resolve(jf));
}
public static class VersionedJarEntry
{
final JarEntry entry;
final String name;
final int version;
final boolean inner;
final String outer;
VersionedJarEntry(JarEntry entry)
{
int v = 0;
String name = entry.getName();
if (name.startsWith(META_INF_VERSIONS))
{
v=-1;
int index = name.indexOf('/', META_INF_VERSIONS.length());
if (index >= 0 && index < name.length())
{
try
{
v = Integer.parseInt(name, META_INF_VERSIONS.length(), index, 10);
name = name.substring(index + 1);
}
catch (NumberFormatException x)
{
}
}
}
this.entry = entry;
this.name = name;
this.version = v;
this.inner = name.contains("$") && name.toLowerCase().endsWith(".class");
this.outer = inner?name.substring(0,name.indexOf('$'))+name.substring(name.length()-6,name.length()):null;
}
boolean isVersioned()
{
return version > 0;
}
boolean isApplicable(int version)
{
return this.version>=0 && this.version <= version;
}
boolean isReplacedBy(VersionedJarEntry entry)
{
return this.name.equals(entry.name) && entry.version>version;
}
@Override
public String toString()
{
return entry.toString() + (version==0?"[base]":("["+version+"]"));
}
public JarEntry resolve(JarFile jf)
{
if (version>0)
return jf.getJarEntry(name);
return entry;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment