Ho una classe Formula
, che si trova nella confezione javaapplication4
, che mi carico con un URLClassLoader. Tuttavia, quando lo chiamo da un'altra classe Test1
, che si trova nello stesso pacchetto, non posso accedere ai suoi metodi che hanno un modificatore di accesso predefinito (posso accedere ai metodi pubblici).URLClassLoader e l'accessibilità dei metodi del pacchetto-privato
ottengo la seguente eccezione:
java.lang.IllegalAccessException: Classe javaapplication4.Test1 non può accedere a un membro della classe di javaapplication4.Formula con modificatori ""
Come posso accedere ai metodi package-private di una classe caricata in runtime dallo stesso pacchetto?
Suppongo che sia un problema con l'utilizzo di un caricatore di classi diverso, ma non sono sicuro del perché (ho impostato il genitore di URLClassLoader).
SSCCE riprodurre il problema (percorsi di Windows) - suppongo che il problema è nel metodo loadClass
:
public class Test1 {
private static final Path TEMP_PATH = Paths.get("C:/temp/");
public static void main(String[] args) throws Exception {
String thisPackage = Test1.class.getPackage().getName();
String className = thisPackage + ".Formula"; //javaapplication4.Formula
String body = "package " + thisPackage + "; "
+ "public class Formula { "
+ " double calculateFails() { "
+ " return 123; "
+ " } "
+ " public double calculate() {"
+ " return 123; "
+ " } "
+ "} ";
compile(className, body, TEMP_PATH);
Class<?> formulaClass = loadClass(className, TEMP_PATH);
Method calculate = formulaClass.getDeclaredMethod("calculate");
double value = (double) calculate.invoke(formulaClass.newInstance());
//next line prints 123
System.out.println("value = " + value);
Method calculateFails = formulaClass.getDeclaredMethod("calculateFails");
//next line throws exception:
double valueFails = (double) calculateFails.invoke(formulaClass.newInstance());
System.out.println("valueFails = " + valueFails);
}
private static Class<?> loadClass(String className, Path path) throws Exception {
URLClassLoader loader = new URLClassLoader(new URL[]{path.toUri().toURL()}, Test1.class.getClassLoader());
return loader.loadClass(className);
}
private static void compile(String className, String body, Path path) throws Exception {
List<JavaSourceFromString> sourceCode = Arrays.asList(new JavaSourceFromString(className, body));
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(path.toFile()));
boolean ok = compiler.getTask(null, fileManager, null, null, null, sourceCode).call();
System.out.println("compilation ok = " + ok);
}
public static class JavaSourceFromString extends SimpleJavaFileObject {
final String code;
JavaSourceFromString(String name, String code) {
super(URI.create("string:///" + name.replace('.', '/') + JavaFileObject.Kind.SOURCE.extension),
JavaFileObject.Kind.SOURCE);
this.code = code;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return code;
}
}
}
Hai provato a utilizzare 'URLClassLoader.newInstance()'? (edit: probabilmente non fa la differenza) – fge
@fge Stesso comportamento – assylias
Il tuo codice non è stato compilato per me, ho dovuto cambiare 'double' per' Double' ovunque (Oracle JDK 1.7u10) – fge