From 3834df5d5b9d885c890b69c401ae61ea2b7fe31e Mon Sep 17 00:00:00 2001 From: matteo-gallo-bb Date: Fri, 16 Mar 2018 12:36:12 +0000 Subject: [PATCH 1/4] Fixed classpath build when the classloader contains jar URIs. --- src/main/java/com/mysema/codegen/SimpleCompiler.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/mysema/codegen/SimpleCompiler.java b/src/main/java/com/mysema/codegen/SimpleCompiler.java index ae207e4..fb60717 100644 --- a/src/main/java/com/mysema/codegen/SimpleCompiler.java +++ b/src/main/java/com/mysema/codegen/SimpleCompiler.java @@ -14,6 +14,7 @@ package com.mysema.codegen; import java.io.*; +import java.net.JarURLConnection; import java.net.URL; import java.net.URLClassLoader; import java.net.URLDecoder; @@ -68,6 +69,11 @@ public static String getClassPath(URLClassLoader cl) { ClassLoader c = cl; while (c instanceof URLClassLoader) { for (URL url : ((URLClassLoader)c).getURLs()) { + if (url.openConnection() instanceof JarURLConnection) { + // extract the file URL from the jar URL + JarURLConnection connection = (JarURLConnection) url.openConnection(); + url = connection.getJarFileURL(); + } String decodedPath = URLDecoder.decode(url.getPath(), "UTF-8"); paths.add(new File(decodedPath).getAbsolutePath()); } From 0547be8857ee7ecde48a463b8e1121b596b12f33 Mon Sep 17 00:00:00 2001 From: matteo-gallo-bb Date: Mon, 26 Mar 2018 12:14:35 +0100 Subject: [PATCH 2/4] Fixed classpath build when the classloader contains jar URIs. MemFileManager can now list Java class files that are packaged in a JAR. --- .../codegen/CompiledJavaFileObject.java | 125 ++++++++++++++++++ .../com/mysema/codegen/JavaClassesFinder.java | 120 +++++++++++++++++ .../com/mysema/codegen/MemFileManager.java | 64 ++++++--- .../com/mysema/codegen/SimpleCompiler.java | 24 ++-- template.mf | 1 + 5 files changed, 306 insertions(+), 28 deletions(-) create mode 100644 src/main/java/com/mysema/codegen/CompiledJavaFileObject.java create mode 100644 src/main/java/com/mysema/codegen/JavaClassesFinder.java diff --git a/src/main/java/com/mysema/codegen/CompiledJavaFileObject.java b/src/main/java/com/mysema/codegen/CompiledJavaFileObject.java new file mode 100644 index 0000000..a5da29f --- /dev/null +++ b/src/main/java/com/mysema/codegen/CompiledJavaFileObject.java @@ -0,0 +1,125 @@ +/* + * Copyright 2018, The Querydsl Team (http://www.querydsl.com/team) + * + * 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 com.mysema.codegen; + +import java.net.URI; +import java.io.*; +import javax.tools.JavaFileObject; +import javax.lang.model.element.NestingKind; +import javax.lang.model.element.Modifier; + +/** + * CompiledJavaFileObject defines a Java class file object that can be in a folder or in a JAR + * + * @author Matteo Gallo + */ +class CompiledJavaFileObject implements JavaFileObject { + + private final String binaryName; + + private final URI uri; + + private final String name; + + public CompiledJavaFileObject(String binaryName, URI uri) { + this.uri = uri; + this.binaryName = binaryName; + // for FS based URI the path is not null, for JAR URI the scheme specific part is not null + name = uri.getPath() == null ? uri.getSchemeSpecificPart() : uri.getPath(); + } + + @Override + public URI toUri() { + return uri; + } + + @Override + public InputStream openInputStream() throws IOException { + // easy way to handle any URI! + return uri.toURL().openStream(); + } + + @Override + public OutputStream openOutputStream() throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public String getName() { + return name; + } + + @Override + public Reader openReader(boolean ignoreEncodingErrors) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public Writer openWriter() throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public long getLastModified() { + return 0; + } + + @Override + public boolean delete() { + throw new UnsupportedOperationException(); + } + + @Override + public Kind getKind() { + return Kind.CLASS; + } + + @Override + // copied from SimpleJavaFileObject + public boolean isNameCompatible(String simpleName, Kind kind) { + String baseName = simpleName + kind.extension; + return kind.equals(getKind()) + && (baseName.equals(getName()) + || getName().endsWith("/" + baseName)); + } + + @Override + public NestingKind getNestingKind() { + throw new UnsupportedOperationException(); + } + + @Override + public Modifier getAccessLevel() { + throw new UnsupportedOperationException(); + } + + public String binaryName() { + return binaryName; + } + + + @Override + public String toString() { + return "CustomJavaFileObject{" + + "uri=" + uri + + '}'; + } +} diff --git a/src/main/java/com/mysema/codegen/JavaClassesFinder.java b/src/main/java/com/mysema/codegen/JavaClassesFinder.java new file mode 100644 index 0000000..afcaa9d --- /dev/null +++ b/src/main/java/com/mysema/codegen/JavaClassesFinder.java @@ -0,0 +1,120 @@ +/* + * Copyright 2018, The Querydsl Team (http://www.querydsl.com/team) + * + * 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 com.mysema.codegen; + +import javax.tools.JavaFileObject; +import java.io.File; +import java.io.IOException; +import java.net.JarURLConnection; +import java.net.URI; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; + +import static javax.tools.JavaFileObject.Kind.CLASS; + +/** + * JavaClassesFinder finds Java file classes using the specified Classloader + * + * @author Matteo Gallo + */ +class JavaClassesFinder { + + private ClassLoader classLoader; + + public JavaClassesFinder(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + /** + * List all the Java file classes that are present in the specified package. + * + * @param packageName the package name where to + * @return a list of Java file classes + * @throws IOException + */ + public List listAll(String packageName) throws IOException { + String javaPackageName = packageName.replaceAll("\\.", "/"); + + List result = new ArrayList(); + + Enumeration urlEnumeration = classLoader.getResources(javaPackageName); + while (urlEnumeration.hasMoreElements()) { + // one URL for each jar on the classpath that has the given package + URL packageFolderURL = urlEnumeration.nextElement(); + result.addAll(listUnder(packageName, packageFolderURL)); + } + + return result; + } + + private Collection listUnder(String packageName, URL packageFolderURL) { + File directory = new File(packageFolderURL.getFile()); + if (directory.isDirectory()) { + // browse local .class files - useful for local execution + return processDir(packageName, directory); + } else { + // browse a jar file + return processJar(packageFolderURL); + } + } + + private List processJar(URL packageFolderURL) { + List result = new ArrayList(); + try { + JarURLConnection jarConn = (JarURLConnection) packageFolderURL.openConnection(); + String jarUri = jarConn.getJarFileURL().toString(); + String rootEntryName = jarConn.getEntryName(); + int rootEnd = rootEntryName.length() + 1; + + Enumeration entryEnum = jarConn.getJarFile().entries(); + while (entryEnum.hasMoreElements()) { + JarEntry jarEntry = entryEnum.nextElement(); + String name = jarEntry.getName(); + if (name.startsWith(rootEntryName) && name.indexOf('/', rootEnd) == -1 && name.endsWith(CLASS.extension)) { + URI uri = URI.create(jarUri + "!/" + name); + String binaryName = name.replaceAll("/", "."); + binaryName = binaryName.replaceAll(CLASS.extension + "$", ""); + + result.add(new CompiledJavaFileObject(binaryName, uri)); + } + } + } catch (Exception e) { + throw new CodegenException("Wasn't able to open " + packageFolderURL + " as a jar file", e); + } + return result; + } + + private List processDir(String packageName, File directory) { + List result = new ArrayList(); + + File[] childFiles = directory.listFiles(); + for (File childFile : childFiles) { + // We only want the .class files + if (childFile.isFile() && childFile.getName().endsWith(CLASS.extension)) { + String binaryName = packageName + "." + childFile.getName(); + binaryName = binaryName.replaceAll(CLASS.extension + "$", ""); + + result.add(new CompiledJavaFileObject(binaryName, childFile.toURI())); + } + } + + return result; + } +} \ No newline at end of file diff --git a/src/main/java/com/mysema/codegen/MemFileManager.java b/src/main/java/com/mysema/codegen/MemFileManager.java index a4ca488..c9f1bdc 100644 --- a/src/main/java/com/mysema/codegen/MemFileManager.java +++ b/src/main/java/com/mysema/codegen/MemFileManager.java @@ -1,10 +1,12 @@ /* - * Copyright 2010, Mysema Ltd - * + * Copyright 2018, The Querydsl Team (http://www.querydsl.com/team) + * * 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 + * + * 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. @@ -43,6 +45,8 @@ public class MemFileManager extends ForwardingJavaFileManager { private final String urlPrefix; + private final JavaClassesFinder finder; + public MemFileManager(ClassLoader parent, StandardJavaFileManager sjfm) { super(sjfm); ramFileSystem = new HashMap>(); @@ -51,6 +55,7 @@ public MemFileManager(ClassLoader parent, StandardJavaFileManager sjfm) { classLoaderContent); classLoader = new MemClassLoader(parent, ramFileSystem); urlPrefix = MemFileSystemRegistry.DEFAULT.getUrlPrefix(this); + finder = new JavaClassesFinder(classLoader); } @Override @@ -117,6 +122,8 @@ public String inferBinaryName(Location loc, JavaFileObject javaFileObject) { String result; if (loc == StandardLocation.CLASS_PATH && javaFileObject instanceof MemJavaFileObject) { result = javaFileObject.getName(); + } else if (javaFileObject instanceof CompiledJavaFileObject) { + result = ((CompiledJavaFileObject) javaFileObject).binaryName(); } else { result = super.inferBinaryName(loc, javaFileObject); } @@ -133,9 +140,27 @@ public Iterable list(Location location, String pkg, Set ki boolean recurse) throws IOException { List result = new ArrayList(); - for (JavaFileObject f : super.list(location, pkg, kinds, recurse)) { - result.add(f); + + if (location == StandardLocation.PLATFORM_CLASS_PATH) { + // let standard manager handle + return super.list(location, pkg, kinds, recurse); + } else if (location == StandardLocation.CLASS_PATH && kinds.contains(JavaFileObject.Kind.CLASS)) { + for (JavaFileObject f : super.list(location, pkg, kinds, recurse)) { + result.add(f); + } + // app specific classes are here + result.addAll(finder.listAll(pkg)); } + + // here we add to the results the classes that Codegen has generated and has put in memory + result.addAll(addInMemoryClasses(location, pkg, kinds, recurse)); + + return result; + } + + private List addInMemoryClasses(Location location, String pkg, Set kinds, boolean recurse) { + List result = new ArrayList(); + if (location == StandardLocation.CLASS_PATH) { location = StandardLocation.CLASS_OUTPUT; } @@ -145,23 +170,32 @@ public Iterable list(Location location, String pkg, Set ki if (ramFileSystem.containsKey(key)) { Map locatedFiles = ramFileSystem.get(key); for (Map.Entry entry : locatedFiles.entrySet()) { - String name = entry.getKey(); - String packageName = ""; - if (name.indexOf('.') > -1) { - packageName = name.substring(0, name.lastIndexOf('.')); - } - if (recurse ? packageName.startsWith(pkg) : packageName.equals(pkg)) { - JavaFileObject candidate = entry.getValue(); - if (kinds.contains(candidate.getKind())) { - result.add(candidate); - } + JavaFileObject processedFile = processLocatedFile(pkg, kinds, recurse, entry); + if (processedFile != null) { + result.add(processedFile); } } } } + return result; } + private JavaFileObject processLocatedFile(String pkg, Set kinds, boolean recurse, Map.Entry entry) { + String name = entry.getKey(); + String packageName = ""; + if (name.indexOf('.') > -1) { + packageName = name.substring(0, name.lastIndexOf('.')); + } + if (recurse ? packageName.startsWith(pkg) : packageName.equals(pkg)) { + JavaFileObject candidate = entry.getValue(); + if (kinds.contains(candidate.getKind())) { + return candidate; + } + } + return null; + } + private void register(LocationAndKind key, JavaFileObject javaFileObject) { if (!ramFileSystem.containsKey(key)) { ramFileSystem.put(key, new HashMap()); diff --git a/src/main/java/com/mysema/codegen/SimpleCompiler.java b/src/main/java/com/mysema/codegen/SimpleCompiler.java index fb60717..c1ace6c 100644 --- a/src/main/java/com/mysema/codegen/SimpleCompiler.java +++ b/src/main/java/com/mysema/codegen/SimpleCompiler.java @@ -1,10 +1,12 @@ /* - * Copyright 2010, Mysema Ltd - * + * Copyright 2018, The Querydsl Team (http://www.querydsl.com/team) + * * 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 + * + * 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. @@ -14,10 +16,7 @@ package com.mysema.codegen; import java.io.*; -import java.net.JarURLConnection; -import java.net.URL; -import java.net.URLClassLoader; -import java.net.URLDecoder; +import java.net.*; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; @@ -70,16 +69,15 @@ public static String getClassPath(URLClassLoader cl) { while (c instanceof URLClassLoader) { for (URL url : ((URLClassLoader)c).getURLs()) { if (url.openConnection() instanceof JarURLConnection) { - // extract the file URL from the jar URL - JarURLConnection connection = (JarURLConnection) url.openConnection(); - url = connection.getJarFileURL(); + paths.add(url.toString()); + } else { + String decodedPath = URLDecoder.decode(url.getPath(), "UTF-8"); + paths.add(new File(decodedPath).getAbsolutePath()); } - String decodedPath = URLDecoder.decode(url.getPath(), "UTF-8"); - paths.add(new File(decodedPath).getAbsolutePath()); } c = c.getParent(); } - } + } return pathJoiner.join(paths); } catch (UnsupportedEncodingException e) { throw new CodegenException(e); diff --git a/template.mf b/template.mf index adc2cf5..213aca3 100644 --- a/template.mf +++ b/template.mf @@ -5,5 +5,6 @@ Bundle-ManifestVersion: 2 Import-Template: javax.annotation.*;version="0", javax.tools.*;version="0", + javax.lang.*;version="0", org.eclipse.jdt.*;version="3.7.2", com.google.common.*;version="${guava.version}" From 81a09b13550f7863cb88f152baec4cb6f27742d3 Mon Sep 17 00:00:00 2001 From: matteo-gallo-bb Date: Wed, 19 Sep 2018 17:12:58 +0100 Subject: [PATCH 3/4] Adding JavaClassesFinder unit test. Adding atamur and article references. Adding maven compiler source and target Java 6. --- pom.xml | 226 ++++++++---------- .../codegen/CompiledJavaFileObject.java | 15 +- .../com/mysema/codegen/JavaClassesFinder.java | 9 +- .../mysema/codegen/JavaClassesFinderTest.java | 133 +++++++++++ 4 files changed, 253 insertions(+), 130 deletions(-) create mode 100644 src/test/java/com/mysema/codegen/JavaClassesFinderTest.java diff --git a/pom.xml b/pom.xml index 21c638f..b08681e 100644 --- a/pom.xml +++ b/pom.xml @@ -1,126 +1,110 @@ - + - 4.0.0 - com.mysema.codegen - codegen - 0.6.9.BUILD-SNAPSHOT - Codegen - Code generation and compilation for Java - - - com.mysema.home - mysema-source - 0.3.1 - - - jar + 4.0.0 + com.mysema.codegen + codegen + 0.6.9.BUILD-SNAPSHOT + Codegen + Code generation and compilation for Java - 2010 - - - - Apache License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - - - - - scm:git:git@github.com:querydsl/codegen.git - git@github.com:querydsl/codegen.git - - - - 4.01 - 3.0.1 - 11.0.2 - 4.3.1 - - - - - com.google.guava - guava - 18.0 - - - - org.eclipse.jdt.core.compiler - ecj - ${ecj.version} - - - - - junit - junit - 4.8.1 - test - - - javax.servlet - servlet-api - - - - - javax.validation - validation-api - 1.0.CR3 - test - - - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - true - - - - com.springsource.bundlor - com.springsource.bundlor.maven - 1.0.0.RELEASE - - - bundlor - - bundlor - - - - - true - - - - - - - - - - com.springsource.repository.bundles.release - http://repository.springsource.com/maven/bundles/release - - + + com.mysema.home + mysema-source + 0.3.1 + + + jar + + 2010 + + + + Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + + scm:git:git@github.com:querydsl/codegen.git + git@github.com:querydsl/codegen.git + + + + 1.6 + 1.6 + 4.01 + 3.0.1 + 11.0.2 + 4.3.1 + + + + + com.google.guava + guava + 18.0 + + + + org.eclipse.jdt.core.compiler + ecj + ${ecj.version} + + + + + junit + junit + 4.8.1 + test + + + javax.servlet + servlet-api + + + + + javax.validation + validation-api + 1.0.CR3 + test + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + com.springsource.bundlor + com.springsource.bundlor.maven + 1.0.0.RELEASE + + + bundlor + + bundlor + + + + + true + + + + + + + + com.springsource.repository.bundles.release + http://repository.springsource.com/maven/bundles/release + + diff --git a/src/main/java/com/mysema/codegen/CompiledJavaFileObject.java b/src/main/java/com/mysema/codegen/CompiledJavaFileObject.java index a5da29f..ab22f73 100644 --- a/src/main/java/com/mysema/codegen/CompiledJavaFileObject.java +++ b/src/main/java/com/mysema/codegen/CompiledJavaFileObject.java @@ -22,9 +22,12 @@ import javax.lang.model.element.Modifier; /** - * CompiledJavaFileObject defines a Java class file object that can be in a folder or in a JAR + * CompiledJavaFileObject defines a Java class file object that can be in a folder or in a JAR. * - * @author Matteo Gallo + * NOTE: This is a derivative work from an article of atamur. + * Original article can be found here: http://atamur.blogspot.com/2009/10/using-built-in-javacompiler-with-custom.html + * + * @author matteo-gallo-bb */ class CompiledJavaFileObject implements JavaFileObject { @@ -53,7 +56,7 @@ public InputStream openInputStream() throws IOException { } @Override - public OutputStream openOutputStream() throws IOException { + public OutputStream openOutputStream() { throw new UnsupportedOperationException(); } @@ -63,17 +66,17 @@ public String getName() { } @Override - public Reader openReader(boolean ignoreEncodingErrors) throws IOException { + public Reader openReader(boolean ignoreEncodingErrors) { throw new UnsupportedOperationException(); } @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + public CharSequence getCharContent(boolean ignoreEncodingErrors) { throw new UnsupportedOperationException(); } @Override - public Writer openWriter() throws IOException { + public Writer openWriter() { throw new UnsupportedOperationException(); } diff --git a/src/main/java/com/mysema/codegen/JavaClassesFinder.java b/src/main/java/com/mysema/codegen/JavaClassesFinder.java index afcaa9d..950acbd 100644 --- a/src/main/java/com/mysema/codegen/JavaClassesFinder.java +++ b/src/main/java/com/mysema/codegen/JavaClassesFinder.java @@ -32,20 +32,23 @@ /** * JavaClassesFinder finds Java file classes using the specified Classloader * - * @author Matteo Gallo + * NOTE: This is a derivative work from an article of atamur. + * Original article can be found here: http://atamur.blogspot.com/2009/10/using-built-in-javacompiler-with-custom.html + * + * @author matteo-gallo-bb */ class JavaClassesFinder { private ClassLoader classLoader; - public JavaClassesFinder(ClassLoader classLoader) { + JavaClassesFinder(ClassLoader classLoader) { this.classLoader = classLoader; } /** * List all the Java file classes that are present in the specified package. * - * @param packageName the package name where to + * @param packageName * @return a list of Java file classes * @throws IOException */ diff --git a/src/test/java/com/mysema/codegen/JavaClassesFinderTest.java b/src/test/java/com/mysema/codegen/JavaClassesFinderTest.java new file mode 100644 index 0000000..fb24fb6 --- /dev/null +++ b/src/test/java/com/mysema/codegen/JavaClassesFinderTest.java @@ -0,0 +1,133 @@ +/* + * Copyright 2018, The Querydsl Team (http://www.querydsl.com/team) + * + * 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 com.mysema.codegen; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import javax.tools.JavaFileObject; +import java.io.*; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Enumeration; +import java.util.List; +import java.util.Vector; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; + +/** + * JavaClassesFinder unit test + * + * @author matteo-gallo-bb + */ +public class JavaClassesFinderTest { + + private File tmpBaseDir; + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Before + public void setUp() { + tmpBaseDir = temporaryFolder.newFolder("javaClassesFinderTest"); + } + + @Test + public void listAll() throws IOException { + // given + File bootJarFile = createSampleJarFile(); + String bootJarFilePath = bootJarFile.getAbsolutePath(); + JavaClassesFinder finder = new JavaClassesFinder(new ClassLoaderMock(bootJarFilePath)); + + // when + List javaFileObjectList = finder.listAll("com.mysema.codegen.model"); + + // then + assertNotNull(javaFileObjectList); + assertEquals(1, javaFileObjectList.size()); + assertTrue(javaFileObjectList.get(0) instanceof CompiledJavaFileObject); + CompiledJavaFileObject javaFileObject = (CompiledJavaFileObject) javaFileObjectList.get(0); + assertEquals("com.mysema.codegen.model.ClassType", javaFileObject.binaryName()); + assertEquals(bootJarFilePath + "!/com/mysema/codegen/model/ClassType.class", javaFileObject.getName()); + } + + private File createSampleJarFile() throws IOException { + File classTypeFile = createAndWriteTmpClassFile("ClassType.class"); + + //create a boot jar file + File bootJar = new File(tmpBaseDir,"exampleBoot.jar"); + FileOutputStream outputStream = new FileOutputStream(bootJar); + ZipOutputStream sampleJar = new ZipOutputStream(outputStream); + + // adding ClassType file and folders to boot jar file + sampleJar.putNextEntry(new ZipEntry("com/")); + sampleJar.putNextEntry(new ZipEntry("com/mysema/")); + sampleJar.putNextEntry(new ZipEntry("com/mysema/codegen/")); + sampleJar.putNextEntry(new ZipEntry("com/mysema/codegen/model/")); + ZipEntry zeClassType = new ZipEntry("com/mysema/codegen/model/" + classTypeFile.getName()); + sampleJar.putNextEntry(zeClassType); + + // writing ClassType file in boot jar file + FileInputStream inputStream = new FileInputStream(classTypeFile); + byte[] buffer = new byte[1024]; + for (int len; (len = inputStream.read(buffer)) > 0;) { + sampleJar.write(buffer, 0, len); + } + inputStream.close(); + sampleJar.closeEntry(); + + sampleJar.close(); + + return bootJar; + } + + private File createAndWriteTmpClassFile(String fileName) throws IOException { + //create a temp class file + File classTypeFile = new File(tmpBaseDir, fileName); + + //write it + BufferedWriter bw = new BufferedWriter(new FileWriter(classTypeFile)); + bw.write("This is the temporary file content"); + bw.close(); + + return classTypeFile; + } + + private class ClassLoaderMock extends ClassLoader { + + private String libraryFilePath; + + private ClassLoaderMock(String libraryFilePath) { + this.libraryFilePath = libraryFilePath; + } + + @Override + public Enumeration getResources(String name) { + Vector urlVector = new Vector(); + try { + urlVector.add(new URL("jar:file:" + libraryFilePath + "!/com/mysema/codegen/model/")); + } catch (MalformedURLException e) { + fail("File " + libraryFilePath + " not found!"); + } + return urlVector.elements(); + } + } +} \ No newline at end of file From 592e70f33d3446d879ec26dd09e3f45b732ff474 Mon Sep 17 00:00:00 2001 From: matteo-gallo-bb Date: Fri, 28 Sep 2018 14:54:19 +0100 Subject: [PATCH 4/4] Updating testing libraries. Fixed bug when getting Jar URL like: "jar:file:/temp/boot.jar!/" indicating the Root folder of the Jar. Updated unit test. --- pom.xml | 14 ++--- .../com/mysema/codegen/JavaClassesFinder.java | 2 +- .../mysema/codegen/JavaClassesFinderTest.java | 60 ++++++++++++++----- 3 files changed, 52 insertions(+), 24 deletions(-) diff --git a/pom.xml b/pom.xml index b08681e..b84c325 100644 --- a/pom.xml +++ b/pom.xml @@ -57,14 +57,8 @@ junit junit - 4.8.1 + 4.12 test - - - javax.servlet - servlet-api - - javax.validation @@ -72,6 +66,12 @@ 1.0.CR3 test + + pl.pragmatists + JUnitParams + 1.1.1 + test + diff --git a/src/main/java/com/mysema/codegen/JavaClassesFinder.java b/src/main/java/com/mysema/codegen/JavaClassesFinder.java index 950acbd..eb91b2b 100644 --- a/src/main/java/com/mysema/codegen/JavaClassesFinder.java +++ b/src/main/java/com/mysema/codegen/JavaClassesFinder.java @@ -83,7 +83,7 @@ private List processJar(URL packageFolderURL) { try { JarURLConnection jarConn = (JarURLConnection) packageFolderURL.openConnection(); String jarUri = jarConn.getJarFileURL().toString(); - String rootEntryName = jarConn.getEntryName(); + String rootEntryName = jarConn.getEntryName() != null ? jarConn.getEntryName() : ""; int rootEnd = rootEntryName.length() + 1; Enumeration entryEnum = jarConn.getJarFile().entries(); diff --git a/src/test/java/com/mysema/codegen/JavaClassesFinderTest.java b/src/test/java/com/mysema/codegen/JavaClassesFinderTest.java index fb24fb6..431e3cb 100644 --- a/src/test/java/com/mysema/codegen/JavaClassesFinderTest.java +++ b/src/test/java/com/mysema/codegen/JavaClassesFinderTest.java @@ -15,10 +15,13 @@ */ package com.mysema.codegen; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; import javax.tools.JavaFileObject; import java.io.*; @@ -30,6 +33,7 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import static javax.tools.JavaFileObject.Kind.CLASS; import static org.junit.Assert.*; import static org.junit.Assert.assertEquals; @@ -38,45 +42,54 @@ * * @author matteo-gallo-bb */ +@RunWith(JUnitParamsRunner.class) public class JavaClassesFinderTest { private File tmpBaseDir; + private File bootJarFile; @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); @Before - public void setUp() { + public void setUp() throws IOException { tmpBaseDir = temporaryFolder.newFolder("javaClassesFinderTest"); + bootJarFile = createSampleJarFile(); } + @Parameters({"com.mysema.codegen.model, ClassType", ", ClassRoot"}) @Test - public void listAll() throws IOException { + public void listAll(String packageName, String className) throws IOException { // given - File bootJarFile = createSampleJarFile(); String bootJarFilePath = bootJarFile.getAbsolutePath(); JavaClassesFinder finder = new JavaClassesFinder(new ClassLoaderMock(bootJarFilePath)); // when - List javaFileObjectList = finder.listAll("com.mysema.codegen.model"); + List javaFileObjectList = finder.listAll(packageName); // then assertNotNull(javaFileObjectList); assertEquals(1, javaFileObjectList.size()); assertTrue(javaFileObjectList.get(0) instanceof CompiledJavaFileObject); CompiledJavaFileObject javaFileObject = (CompiledJavaFileObject) javaFileObjectList.get(0); - assertEquals("com.mysema.codegen.model.ClassType", javaFileObject.binaryName()); - assertEquals(bootJarFilePath + "!/com/mysema/codegen/model/ClassType.class", javaFileObject.getName()); + assertEquals(getFullQualifiedClassName(packageName, className), javaFileObject.binaryName()); + assertEquals(bootJarFilePath + "!/" + fromPackageToFolder(packageName, className), javaFileObject.getName()); } private File createSampleJarFile() throws IOException { File classTypeFile = createAndWriteTmpClassFile("ClassType.class"); + File classRootFile = createAndWriteTmpClassFile("ClassRoot.class"); //create a boot jar file File bootJar = new File(tmpBaseDir,"exampleBoot.jar"); FileOutputStream outputStream = new FileOutputStream(bootJar); ZipOutputStream sampleJar = new ZipOutputStream(outputStream); + // adding ClassRoot file to boot jar file + ZipEntry zeClassRoot = new ZipEntry(classRootFile.getName()); + sampleJar.putNextEntry(zeClassRoot); + writeTmpClassFileInJar(classRootFile, sampleJar); + // adding ClassType file and folders to boot jar file sampleJar.putNextEntry(new ZipEntry("com/")); sampleJar.putNextEntry(new ZipEntry("com/mysema/")); @@ -84,15 +97,7 @@ private File createSampleJarFile() throws IOException { sampleJar.putNextEntry(new ZipEntry("com/mysema/codegen/model/")); ZipEntry zeClassType = new ZipEntry("com/mysema/codegen/model/" + classTypeFile.getName()); sampleJar.putNextEntry(zeClassType); - - // writing ClassType file in boot jar file - FileInputStream inputStream = new FileInputStream(classTypeFile); - byte[] buffer = new byte[1024]; - for (int len; (len = inputStream.read(buffer)) > 0;) { - sampleJar.write(buffer, 0, len); - } - inputStream.close(); - sampleJar.closeEntry(); + writeTmpClassFileInJar(classTypeFile, sampleJar); sampleJar.close(); @@ -111,6 +116,28 @@ private File createAndWriteTmpClassFile(String fileName) throws IOException { return classTypeFile; } + private void writeTmpClassFileInJar(File classTypeFile, ZipOutputStream sampleJar) throws IOException { + // writing temp class file in given jar file + FileInputStream inputStream = new FileInputStream(classTypeFile); + byte[] buffer = new byte[1024]; + for (int len; (len = inputStream.read(buffer)) > 0;) { + sampleJar.write(buffer, 0, len); + } + inputStream.close(); + sampleJar.closeEntry(); + } + + private String fromPackageToFolder(String packageName, String className) { + if (packageName.equals("")) { + return className + CLASS.extension; + } + return packageName.replaceAll("\\.", "/") + "/" + className + CLASS.extension; + } + + private String getFullQualifiedClassName(String packageName, String className) { + return packageName.equals("") ? className : packageName + "." + className; + } + private class ClassLoaderMock extends ClassLoader { private String libraryFilePath; @@ -123,7 +150,8 @@ private ClassLoaderMock(String libraryFilePath) { public Enumeration getResources(String name) { Vector urlVector = new Vector(); try { - urlVector.add(new URL("jar:file:" + libraryFilePath + "!/com/mysema/codegen/model/")); + String path = name.equals("") ? name : name + "/"; + urlVector.add(new URL("jar:file:" + libraryFilePath + "!/" + path)); } catch (MalformedURLException e) { fail("File " + libraryFilePath + " not found!"); }