@@ -0,0 +1,46 @@ | |||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> | |||
<html> <head> | |||
<title>AspectJ 1.9.4 Readme</title> | |||
<style type="text/css"> | |||
<!-- | |||
P { margin-left: 20px; } | |||
PRE { margin-left: 20px; } | |||
LI { margin-left: 20px; } | |||
H4 { margin-left: 20px; } | |||
H3 { margin-left: 10px; } | |||
--> | |||
</style> | |||
</head> | |||
<body> | |||
<div align="right"><small> | |||
© Copyright 2019 Contributors. | |||
All rights reserved. | |||
</small></div> | |||
<p>The full list of resolved issues in 1.9.4 is available | |||
<a href="https://bugs.eclipse.org/bugs/buglist.cgi?bug_status=RESOLVED&bug_status=VERIFIED&bug_status=CLOSED&f0=OP&f1=OP&f3=CP&f4=CP&j1=OR&list_id=16866879&product=AspectJ&query_format=advanced&target_milestone=1.9.4">here</a></h2>.</p> | |||
<p>AspectJ 1.9.4 has a couple of important fixes in it: | |||
<ul> | |||
<li>Due to the new maven build process being used to build release artifacts | |||
for the first time, there were errors in the aspectjweaver jar that affected | |||
the ability to use it on the command line as an agent, | |||
this is now fixed. | |||
<li>A number of users were noticing a ClassCastException problem, which I believe was due to trying to | |||
run AspectJ on one level of the JDK whilst targeting another. This can happen quite easily in eclipse | |||
if running your Eclipse on Java 8 but developing projects targeting Java 11. | |||
The class cast is because Java8 couldn't understand | |||
the packaging of system classes post Java9 and so couldn't find java.lang.Object. This has now all been | |||
tidied up and should work much better. More details in <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=546807">546807</a>, | |||
thanks to Denys Khanzhyiev for some tips on getting to the right solution. | |||
</ul> | |||
<p>Available: 1.9.4 available 10-May-2019</p> | |||
<br><br> | |||
<!-- ============================== --> | |||
</body> | |||
</html> |
@@ -138,6 +138,7 @@ | |||
<tr> <td>README's | |||
</td> | |||
<td>Changes and porting guide for AspectJ | |||
<a href="README-194.html">1.9.4</a>, | |||
<a href="README-193.html">1.9.3</a>, | |||
<a href="README-192.html">1.9.2</a>, | |||
<a href="README-191.html">1.9.1</a>, |
@@ -6,7 +6,7 @@ | |||
<parent> | |||
<groupId>org.aspectj</groupId> | |||
<artifactId>aspectj-parent</artifactId> | |||
<version>1.9.3.BUILD-SNAPSHOT</version> | |||
<version>1.9.4.BUILD-SNAPSHOT</version> | |||
<relativePath>..</relativePath> | |||
</parent> | |||
@@ -33,7 +33,7 @@ | |||
<configuration> | |||
<groupId>org.aspectj</groupId> | |||
<artifactId>org.eclipse.jdt.core</artifactId> | |||
<version>1.9.3.BUILD-SNAPSHOT</version> | |||
<version>1.9.4.BUILD-SNAPSHOT</version> | |||
<packaging>jar</packaging> | |||
<file>${basedir}/jdtcore-for-aspectj.jar</file> | |||
<createChecksum>true</createChecksum> | |||
@@ -49,7 +49,7 @@ | |||
<configuration> | |||
<groupId>org.aspectj</groupId> | |||
<artifactId>org.eclipse.jdt.core</artifactId> | |||
<version>1.9.3.BUILD-SNAPSHOT</version> | |||
<version>1.9.4.BUILD-SNAPSHOT</version> | |||
<packaging>jar</packaging> | |||
<file>${basedir}/jdtcore-for-aspectj-src.zip</file> | |||
<createChecksum>true</createChecksum> |
@@ -5,7 +5,7 @@ | |||
<modelVersion>4.0.0</modelVersion> | |||
<properties> | |||
<revision>1.9.3.BUILD-SNAPSHOT</revision> | |||
<revision>1.9.4.BUILD-SNAPSHOT</revision> | |||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | |||
</properties> | |||
@@ -17,7 +17,10 @@ import java.io.FileInputStream; | |||
import java.io.FileNotFoundException; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.MalformedURLException; | |||
import java.net.URI; | |||
import java.net.URL; | |||
import java.net.URLClassLoader; | |||
import java.nio.file.FileSystem; | |||
import java.nio.file.FileSystems; | |||
import java.nio.file.FileVisitResult; | |||
@@ -105,9 +108,9 @@ public class ClassPathManager { | |||
return; | |||
} | |||
try { | |||
if (lc.endsWith(LangUtil.JRT_FS)) { // Java9 | |||
if (LangUtil.is19VMOrGreater()) { | |||
entries.add(new JImageEntry()); | |||
if (lc.endsWith(LangUtil.JRT_FS)) { // Java9+ | |||
if (LangUtil.is18VMOrGreater()) { | |||
entries.add(new JImageEntry(lc)); | |||
} | |||
} else { | |||
entries.add(new ZipFileEntry(f)); | |||
@@ -316,24 +319,59 @@ public class ClassPathManager { | |||
* helps reduce memory usage but still gives reasonably fast lookup performance. | |||
*/ | |||
static class JImageEntry extends Entry { | |||
// Map from a JRT-FS file to the cache state for that file | |||
private static Map<String, JImageState> states = new HashMap<>(); | |||
private static FileSystem fs = null; | |||
private JImageState state; | |||
private final static Map<String, Path> fileCache = new SoftHashMap<String, Path>(); | |||
private final static Map<String, Path> packageCache = new HashMap<String, Path>(); | |||
private static boolean packageCacheInitialized = false; | |||
// TODO memory management here - is it held onto too long when LTW? | |||
static class JImageState { | |||
private final String jrtFsPath; | |||
private final FileSystem fs; | |||
Map<String,Path> fileCache = new SoftHashMap<String, Path>(); | |||
boolean packageCacheInitialized = false; | |||
Map<String,Path> packageCache = new HashMap<String, Path>(); | |||
public JImageState(String jrtFsPath, FileSystem fs) { | |||
this.jrtFsPath = jrtFsPath; | |||
this.fs = fs; | |||
} | |||
} | |||
public JImageEntry() { | |||
if (fs == null) { | |||
try { | |||
fs = FileSystems.getFileSystem(JRT_URI); | |||
} catch (Throwable t) { | |||
throw new IllegalStateException("Unexpectedly unable to initialize a JRT filesystem", t); | |||
public JImageEntry(String jrtFsPath) { | |||
state = states.get(jrtFsPath); | |||
if (state == null) { | |||
synchronized (states) { | |||
if (state == null) { | |||
URL jrtPath = null; | |||
try { | |||
jrtPath = new File(jrtFsPath).toPath().toUri().toURL(); | |||
} catch (MalformedURLException e) { | |||
System.out.println("Unexpected problem processing "+jrtFsPath+" bad classpath entry? skipping:"+e.getMessage()); | |||
return; | |||
} | |||
String jdkHome = new File(jrtFsPath).getParentFile().getParent(); | |||
FileSystem fs = null; | |||
try { | |||
if (LangUtil.is19VMOrGreater()) { | |||
HashMap<String, String> env = new HashMap<>(); | |||
env.put("java.home", jdkHome); | |||
fs = FileSystems.newFileSystem(JRT_URI, env); | |||
} else { | |||
URLClassLoader loader = new URLClassLoader(new URL[] { jrtPath }); | |||
HashMap<String, ?> env = new HashMap<>(); | |||
fs = FileSystems.newFileSystem(JRT_URI, env, loader); | |||
} | |||
state = new JImageState(jrtFsPath, fs); | |||
states.put(jrtFsPath, state); | |||
buildPackageMap(); | |||
} catch (Throwable t) { | |||
throw new IllegalStateException("Unexpectedly unable to initialize a JRT filesystem", t); | |||
} | |||
} | |||
} | |||
} | |||
buildPackageMap(); | |||
} | |||
class PackageCacheBuilderVisitor extends SimpleFileVisitor<Path> { | |||
@@ -344,7 +382,7 @@ public class ClassPathManager { | |||
if (fnc > 3) { // There is a package name - e.g. /modules/java.base/java/lang/Object.class | |||
Path packagePath = file.subpath(2, fnc-1); // e.g. java/lang | |||
String packagePathString = packagePath.toString(); | |||
packageCache.put(packagePathString, file.subpath(0, fnc-1)); // java/lang -> /modules/java.base/java/lang | |||
state.packageCache.put(packagePathString, file.subpath(0, fnc-1)); // java/lang -> /modules/java.base/java/lang | |||
} | |||
} | |||
return FileVisitResult.CONTINUE; | |||
@@ -355,9 +393,9 @@ public class ClassPathManager { | |||
* Create a map from package names to the specific directory of the package members in the filesystem. | |||
*/ | |||
private synchronized void buildPackageMap() { | |||
if (!packageCacheInitialized) { | |||
packageCacheInitialized = true; | |||
Iterable<java.nio.file.Path> roots = fs.getRootDirectories(); | |||
if (!state.packageCacheInitialized) { | |||
state.packageCacheInitialized = true; | |||
Iterable<java.nio.file.Path> roots = state.fs.getRootDirectories(); | |||
PackageCacheBuilderVisitor visitor = new PackageCacheBuilderVisitor(); | |||
try { | |||
for (java.nio.file.Path path : roots) { | |||
@@ -392,7 +430,7 @@ public class ClassPathManager { | |||
Path filePath = file.subpath(2, fnc); | |||
String filePathString = filePath.toString(); | |||
if (filePathString.equals(name)) { | |||
fileCache.put(filePathString, file); | |||
state.fileCache.put(filePathString, file); | |||
found = file; | |||
return FileVisitResult.TERMINATE; | |||
} | |||
@@ -414,7 +452,7 @@ public class ClassPathManager { | |||
@Override | |||
public ClassFile find(String name) throws IOException { | |||
String fileName = name.replace('.', '/') + ".class"; | |||
Path file = fileCache.get(fileName); | |||
Path file = state.fileCache.get(fileName); | |||
if (file == null) { | |||
// Check the packages map to see if we know about this package | |||
int idx = fileName.lastIndexOf('/'); | |||
@@ -426,7 +464,7 @@ public class ClassPathManager { | |||
String packageName = null; | |||
if (idx !=-1 ) { | |||
packageName = fileName.substring(0, idx); | |||
packageStart = packageCache.get(packageName); | |||
packageStart = state.packageCache.get(packageName); | |||
if (packageStart != null) { | |||
file = searchForFileAndCache(packageStart, fileName); | |||
} | |||
@@ -440,12 +478,12 @@ public class ClassPathManager { | |||
return cf; | |||
} | |||
static Map<String, Path> getPackageCache() { | |||
return packageCache; | |||
Map<String, Path> getPackageCache() { | |||
return state.packageCache; | |||
} | |||
static Map<String, Path> getFileCache() { | |||
return fileCache; | |||
Map<String, Path> getFileCache() { | |||
return state.fileCache; | |||
} | |||
} |
@@ -0,0 +1,214 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2019 Contributors | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Eclipse Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://www.eclipse.org/legal/epl-v10.html | |||
* ******************************************************************/ | |||
package org.aspectj.weaver.bcel; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import java.util.regex.Pattern; | |||
import org.aspectj.apache.bcel.classfile.ClassFormatException; | |||
import org.aspectj.apache.bcel.classfile.ClassParser; | |||
import org.aspectj.apache.bcel.classfile.JavaClass; | |||
import org.aspectj.bridge.AbortException; | |||
import org.aspectj.bridge.IMessage; | |||
import org.aspectj.bridge.IMessage.Kind; | |||
import org.aspectj.bridge.IMessageHandler; | |||
import org.aspectj.util.LangUtil; | |||
import org.aspectj.weaver.UnresolvedType; | |||
import org.aspectj.weaver.bcel.ClassPathManager.ClassFile; | |||
import junit.framework.TestCase; | |||
/** | |||
* Should run these tests 3 times on each JDK level (8, 9, 11). On each one 3 of the | |||
* tests should pass indicating that JDK can successfully access system types in | |||
* each JDK level. | |||
* | |||
* @author Andy Clement | |||
*/ | |||
public class ClasspathManagerTestCase extends TestCase { | |||
// Works on my machine where all jvms under ~/jvms | |||
private static String java18_rtjar = findJvm("j.*18.*","rt.jar"); | |||
private static String java9_jrtfsjar = findJvm("j.*9.*","jrt-fs.jar");; | |||
private static String java11_jrtfsjar = findJvm("j.*11.*","jrt-fs.jar");; | |||
private static String findJvm(String pattern, String jar) { | |||
String start = System.getProperty("user.home")+"/jvms"; | |||
for (File f: new File(start).listFiles()) { | |||
if (f.isDirectory() && Pattern.matches(pattern, f.getName())) { | |||
File result = walk(f, jar); | |||
if (result !=null) { | |||
System.out.println("For "+pattern+" found "+result.getAbsolutePath()); | |||
return result.getAbsolutePath(); | |||
} | |||
} | |||
} | |||
return null; | |||
} | |||
private static File walk(File dir, String jar) { | |||
File[] fs = dir.listFiles(); | |||
if (fs!=null) { | |||
for (File f: fs) { | |||
if (f.getName().equals(jar)) { | |||
return f; | |||
} else if (f.isDirectory()) { | |||
File s = walk(f, jar); | |||
if (s!=null) { | |||
return s; | |||
} | |||
} | |||
} | |||
} | |||
return null; | |||
} | |||
public void testInstructions() { | |||
System.out.println("This test is really only for standalone usage as it need executing on multiple JDK levels"); | |||
} | |||
public void xtestSanity18accessing18RTJAR() throws IOException { | |||
if (LangUtil.getVmVersion()>8) fail("Must be Java 8"); | |||
List<String> classpath = new ArrayList<>(); | |||
classpath.add(java18_rtjar); | |||
ClassPathManager cpm = new ClassPathManager(classpath, new MH()); | |||
ClassFile t = cpm.find(UnresolvedType.forSignature("Ljava/lang/Object;")); | |||
assertNotNull(t); | |||
} | |||
public void xtestJava18accessing11JRT() throws ClassFormatException, IOException { | |||
if (LangUtil.getVmVersion()>8) fail("Must be Java 8"); | |||
List<String> classpath = new ArrayList<>(); | |||
classpath.add(java11_jrtfsjar); | |||
ClassPathManager cpm = new ClassPathManager(classpath, new MH()); | |||
ClassFile t = cpm.find(UnresolvedType.forSignature("Ljava/lang/String;")); | |||
assertNotNull(t); | |||
ClassParser classParser = new ClassParser(t.getInputStream(),t.getPath()); | |||
JavaClass clazz = classParser.parse(); | |||
// isBlank() exists on Java 11 | |||
long c = Arrays.asList(clazz.getMethods()).stream().filter(m -> m.getName().equals("isBlank")).count(); | |||
assertEquals(1,c); | |||
} | |||
public void xtestJava18accessing19JRT() throws ClassFormatException, IOException { | |||
if (LangUtil.getVmVersion()>8) fail("Must be Java 8"); | |||
List<String> classpath = new ArrayList<>(); | |||
classpath.add(java9_jrtfsjar); | |||
ClassPathManager cpm = new ClassPathManager(classpath, new MH()); | |||
ClassFile t = cpm.find(UnresolvedType.forSignature("Ljava/lang/String;")); | |||
assertNotNull(t); | |||
ClassParser classParser = new ClassParser(t.getInputStream(),t.getPath()); | |||
JavaClass clazz = classParser.parse(); | |||
// isBlank() exists on Java 11, but not on Java9 | |||
long c = Arrays.asList(clazz.getMethods()).stream().filter(m -> m.getName().equals("isBlank")).count(); | |||
assertEquals(0,c); | |||
} | |||
public void xtestSanity19accessing18RTJAR() throws IOException { | |||
assertEquals(9.0,LangUtil.getVmVersion()); | |||
List<String> classpath = new ArrayList<>(); | |||
classpath.add(java18_rtjar); | |||
ClassPathManager cpm = new ClassPathManager(classpath, new MH()); | |||
ClassFile t = cpm.find(UnresolvedType.forSignature("Ljava/lang/Object;")); | |||
assertNotNull(t); | |||
} | |||
public void xtestJava19accessing11JRT() throws ClassFormatException, IOException { | |||
assertEquals(9.0,LangUtil.getVmVersion()); | |||
List<String> classpath = new ArrayList<>(); | |||
classpath.add(java11_jrtfsjar); | |||
ClassPathManager cpm = new ClassPathManager(classpath, new MH()); | |||
ClassFile t = cpm.find(UnresolvedType.forSignature("Ljava/lang/String;")); | |||
assertNotNull(t); | |||
ClassParser classParser = new ClassParser(t.getInputStream(),t.getPath()); | |||
JavaClass clazz = classParser.parse(); | |||
// isBlank() exists on Java 11 | |||
long c = Arrays.asList(clazz.getMethods()).stream().filter(m -> m.getName().equals("isBlank")).count(); | |||
assertEquals(1,c); | |||
} | |||
public void xtestJava19accessing19JRT() throws ClassFormatException, IOException { | |||
assertEquals(9.0,LangUtil.getVmVersion()); | |||
List<String> classpath = new ArrayList<>(); | |||
classpath.add(java9_jrtfsjar); | |||
ClassPathManager cpm = new ClassPathManager(classpath, new MH()); | |||
ClassFile t = cpm.find(UnresolvedType.forSignature("Ljava/lang/String;")); | |||
assertNotNull(t); | |||
ClassParser classParser = new ClassParser(t.getInputStream(),t.getPath()); | |||
JavaClass clazz = classParser.parse(); | |||
// isBlank() exists on Java 11, but not on Java9 | |||
long c = Arrays.asList(clazz.getMethods()).stream().filter(m -> m.getName().equals("isBlank")).count(); | |||
assertEquals(0,c); | |||
} | |||
public void xtestSanity11accessing18RTJAR() throws IOException { | |||
assertEquals(11.0,LangUtil.getVmVersion()); | |||
List<String> classpath = new ArrayList<>(); | |||
classpath.add(java18_rtjar); | |||
ClassPathManager cpm = new ClassPathManager(classpath, new MH()); | |||
ClassFile t = cpm.find(UnresolvedType.forSignature("Ljava/lang/Object;")); | |||
assertNotNull(t); | |||
} | |||
public void xtestJava11accessing11JRT() throws ClassFormatException, IOException { | |||
assertEquals(11.0,LangUtil.getVmVersion()); | |||
List<String> classpath = new ArrayList<>(); | |||
classpath.add(java11_jrtfsjar); | |||
ClassPathManager cpm = new ClassPathManager(classpath, new MH()); | |||
ClassFile t = cpm.find(UnresolvedType.forSignature("Ljava/lang/String;")); | |||
assertNotNull(t); | |||
ClassParser classParser = new ClassParser(t.getInputStream(),t.getPath()); | |||
JavaClass clazz = classParser.parse(); | |||
// isBlank() exists on Java 11 | |||
long c = Arrays.asList(clazz.getMethods()).stream().filter(m -> m.getName().equals("isBlank")).count(); | |||
assertEquals(1,c); | |||
} | |||
public void xtestJava11accessing19JRT() throws ClassFormatException, IOException { | |||
assertEquals(11.0,LangUtil.getVmVersion()); | |||
List<String> classpath = new ArrayList<>(); | |||
classpath.add(java9_jrtfsjar); | |||
ClassPathManager cpm = new ClassPathManager(classpath, new MH()); | |||
ClassFile t = cpm.find(UnresolvedType.forSignature("Ljava/lang/String;")); | |||
assertNotNull(t); | |||
ClassParser classParser = new ClassParser(t.getInputStream(),t.getPath()); | |||
JavaClass clazz = classParser.parse(); | |||
// isBlank() exists on Java 11, but not on Java9 | |||
long c = Arrays.asList(clazz.getMethods()).stream().filter(m -> m.getName().equals("isBlank")).count(); | |||
assertEquals(0,c); | |||
} | |||
static class MH implements IMessageHandler { | |||
@Override | |||
public boolean handleMessage(IMessage message) throws AbortException { | |||
System.out.println(message); | |||
return false; | |||
} | |||
@Override | |||
public boolean isIgnoring(Kind kind) { | |||
return false; | |||
} | |||
@Override | |||
public void dontIgnore(Kind kind) { | |||
} | |||
@Override | |||
public void ignore(Kind kind) { | |||
} | |||
} | |||
} |
@@ -70,7 +70,7 @@ public class JImageTestCase extends TestCase { | |||
if (!LangUtil.is19VMOrGreater()) return; | |||
JImageEntry jie = getJImageEntry(); | |||
Map<String, Path> packageCache = JImageEntry.getPackageCache(); | |||
Map<String, Path> packageCache = jie.getPackageCache(); | |||
assertTrue(packageCache.size()>0); | |||
// Note: seems to be about 1625 entries in it for Java9 | |||
Path path = packageCache.get("java/lang"); |