Created
September 16, 2017 06:35
-
-
Save gregw/8f305e369d0b769e9c3fe791a0634b13 to your computer and use it in GitHub Desktop.
Alternate impl of VersionedJarFile that handles inner classes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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