Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
- Load java source files with getResource so java source verticles now work inside a module (fixes eclipse-vertx#444)
- Parse package definition from the java source and resolve java source root path based on that (fixes eclipse-vertx#433)
  • Loading branch information
jannehietamaki committed Jan 5, 2013
1 parent 588b6d8 commit 72d4423
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 14 deletions.
Expand Up @@ -20,6 +20,7 @@
import org.vertx.java.core.logging.impl.LoggerFactory;

import javax.tools.*;
import java.net.URL;
import javax.tools.JavaFileObject.Kind;
import java.io.File;
import java.util.Collections;
Expand All @@ -34,31 +35,28 @@ public class CompilingClassLoader extends ClassLoader {

private static final Logger log = LoggerFactory.getLogger(CompilingClassLoader.class);

private final String className;
private final JavaSourceContext javaSourceContext;
private final MemoryFileManager fileManager;

private static final String FILE_SEP = System.getProperty("file.separator");

public CompilingClassLoader(ClassLoader loader, String sourceName) {
super(loader);
String temp = sourceName.replace(FILE_SEP, ".");
this.className = temp.substring(0, sourceName.length() - Kind.SOURCE.extension.length());
File sourceFile = new File(sourceName).getAbsoluteFile();
URL resource = getResource(sourceName);
if(resource == null) {
throw new RuntimeException("Resource not found: " + sourceName);
}
File sourceFile = new File(resource.getFile());
if (!sourceFile.canRead()) {
throw new RuntimeException("File not found: " + sourceName);
}

this.javaSourceContext = new JavaSourceContext(sourceFile);

try {
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager standardFileManager = javaCompiler.getStandardFileManager(null, null, null);

File sourceRoot;
if (sourceName.contains(FILE_SEP)) {
sourceRoot = new File(".").getAbsoluteFile();
} else {
sourceRoot = sourceFile.getParentFile();
}
standardFileManager.setLocation(StandardLocation.SOURCE_PATH, Collections.singleton(sourceRoot));
standardFileManager.setLocation(StandardLocation.SOURCE_PATH, Collections.singleton(javaSourceContext.getSourceRoot()));
fileManager = new MemoryFileManager(loader, standardFileManager);
JavaFileObject javaFile = standardFileManager.getJavaFileForInput(StandardLocation.SOURCE_PATH, resolveMainClassName(), Kind.SOURCE);
JavaCompiler.CompilationTask task = javaCompiler.getTask(null, fileManager, diagnostics, null, null, Collections.singleton(javaFile));
Expand All @@ -79,7 +77,7 @@ public CompilingClassLoader(ClassLoader loader, String sourceName) {
}

public String resolveMainClassName() {
return className;
return javaSourceContext.getClassName();
}

@Override
Expand Down
@@ -0,0 +1,98 @@
/*
* Copyright 2013 the original author or authors.
*
* 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 org.vertx.java.deploy.impl.java;

import org.vertx.java.core.logging.Logger;
import org.vertx.java.core.logging.impl.LoggerFactory;

import javax.tools.*;
import java.util.List;
import java.net.URL;
import javax.tools.JavaFileObject.Kind;
import java.io.*;
import java.nio.file.Files;
import java.nio.charset.StandardCharsets;
import java.util.Collections;

/**
*
* Resolves package name and source path based on a single Java source file.
*
* @author Janne Hietam&auml;ki
*/
public class JavaSourceContext {
private static final String FILE_SEP = System.getProperty("file.separator");
private final static String REMOVE_COMMENTS_REGEXP = "(?://.*)|(/\\*(?:.|[\\n\\r])*?\\*/)";

private final String className;
private final File sourceRoot;

public JavaSourceContext(File file) {
String packageName = parsePackage(file);
File rootDirectory = file.getParentFile();
if(packageName != null) {
for(String token : packageName.split("\\.")) {
if(!token.equals(rootDirectory.getName())) {
throw new RuntimeException("Package structure does not match directory structure: " + token + " != " + rootDirectory.getName());
}
rootDirectory = rootDirectory.getParentFile();
}
}
sourceRoot = rootDirectory;

String fileName = file.getName();
String className = fileName.substring(0, fileName.length() - Kind.SOURCE.extension.length());
if(packageName != null) {
className = packageName + "." + className;
}
this.className = className;
}

public File getSourceRoot() {
return sourceRoot;
}

public String getClassName() {
return className;
}

/*
* Parse package definition from a Java source file:
* First remove all comments, split file into lines, find first non-empty line
* Then, if the line starts with keyword "package", parse the package definition from it.
*
*/
private String parsePackage(File file) {
try {
String source = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
source = source.replaceAll(REMOVE_COMMENTS_REGEXP, " ");
for(String line : source.split("\\r?\\n")) {
line = line.trim();
if(line.length() > 0) {
int idx = line.indexOf("package ");
if(idx != -1) {
return line.substring(line.indexOf(" ", idx), line.indexOf(";", idx)).trim();
}
return null; // Package definition must be on the first non-comment line
}
}
return null;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

0 comments on commit 72d4423

Please sign in to comment.