Why the Class cannot be seen in its source file Java - java

Whatever I do I cannot create new instance of class Serwer. Please help, somehow constructor is invisible. I don't understand why is it so. The constructor is public and everything is coded in one file.
I just get this:
java.rmi.StubNotFoundException: Stub class not found: Serwer_Stub; nested exception is:
java.lang.ClassNotFoundException: Serwer_Stub
at sun.rmi.server.Util.createStub(Unknown Source)
at sun.rmi.server.Util.createProxy(Unknown Source)
at sun.rmi.server.UnicastServerRef.exportObject(Unknown Source)
at java.rmi.server.UnicastRemoteObject.exportObject(Unknown Source)
at java.rmi.server.UnicastRemoteObject.exportObject(Unknown Source)
at com.sun.corba.se.impl.javax.rmi.PortableRemoteObject.exportObject(Unknown Source)
at javax.rmi.PortableRemoteObject.exportObject(Unknown Source)
at javax.rmi.PortableRemoteObject.<init>(Unknown Source)
at Serwer.<init>(Serwer.java:13)
at Serwer.main(Serwer.java:35)
Caused by: java.lang.ClassNotFoundException: Serwer_Stub
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
... 10 more
CLASS
import java.rmi.RemoteException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.rmi.PortableRemoteObject;
public class Serwer extends PortableRemoteObject implements MyInterface {
public Serwer() throws RemoteException {
super();
try{
Serwer ref =
new Serwer();
Context ctx = new InitialContext();
ctx.rebind("myinterfaceimplementacja", ref);
}catch(Exception e){e.printStackTrace();}
}
#Override
public String echo(String napis) throws RemoteException {
return "echo" + napis;
}
#Override
public int dodaj(int wrt1, int wrt2) throws RemoteException {
return wrt1 + wrt2;
}
public static void main(String[] args){
try {
new Serwer();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

There are two bugs in your code. The first one is the obvious infinite recursion in the Serwer constructor, where you are calling the constructor again and again. This can be fixed by removing that line from the constructor and replace ref with this on the following line:
public class Serwer extends PortableRemoteObject implements MyInterface {
public Serwer() throws RemoteException {
super();
}
#Override
public String echo(String napis) throws RemoteException {
return "echo" + napis;
}
#Override
public int dodaj(int wrt1, int wrt2) throws RemoteException {
return wrt1 + wrt2;
}
public static void main(String[] args){
try {
Serwer ref = new Serwer();
// Context ctx = new InitialContext();
// ctx.rebind("myinterfaceimplementacja", ref);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
However, this bug is unrelated to the ClassNotFoundException you got. What causes the exception is that you use PortableRemoteObject as the base class of your remote implementation. Normally in Java RMI, the stub class (Serwer_Stub) is generated automatically when you export (instantiate) the remote object. But the PortableRemoteObject is an exception to this case. You can solve this two ways:
As Kumar suggested, replace the javax.rmi.PortableRemoteObject with java.rmi.server.UnicastRemoteObject. This way the stub object gets created automatically, and the above code will run happily, I tested it.
public class Serwer extends UnicastRemoteObject implements MyInterface {
If for some reason you must use PortableRemoteObject, then you should generate the stub class manually by using the RMI compiler (rmic) tool that are shipped with the JDK.
First, you compile the Serwer class:
javac Serwer.java
This will generate the Serwer.class file. Then you call the RMIC tool to generate the stub class:
rmic Serwer
This will generate the Serwer_Stub.class file. Now you can run your server:
java Serwer
I also tested this, it starts without any exceptions.
Note that there is another bug in your code with the usage of the Java Naming, causing another exception (NoInitialContextException), but that is also unrelated with the question, that's why I commented it out in the code above. Since I'm no expert in javax.naming, it's up to someone else to help you with that.
Maybe you intended to use RMI registry instead of using Naming by mistake. RMI registry is the native way to bind and lookup remote objects in Java RMI. In this case you should replace the
Context ctx = new InitialContext();
ctx.rebind("myinterfaceimplementacja", ref);
lines with the appropriate RMI registry code:
Registry reg = LocateRegistry.createRegistry(1099);
reg.rebind("myinterfaceimplementacja", ref);
This will create the RMI registry for you on the standard port (1099). If you run your program, the registry will be created and your remote object will be exported and registered under the given name.
The other way is to write
Registry reg = LocateRegistry.getRegistry();
This makes your program to find an existing registry that is already running. You must start the RMI registry before running your program, by calling the remiregistry tool, that is also part of the JDK:
rmiregistry
Now you can compile and you start your program:
javac Serwer.java
java Serwer
It will start and register your remote object implementation in the registry, making it available to be looked up by the clients.

Related

When using Advice of byte buddy, Exception of java.lang.NoClassDefFoundError is throwed

For some reason, I've been analyzing my own old jar file(unfortunately source code's been lost).
I know what part I'm going to find but can't remember where it is.
So decide to use byte buddy to get all the run flow of jar file. It's enough to log parameter values and return values of all methods in all classes(except library class, e.g, java.lang.*).
I tried sample codes with a little modification, but straggle with just an exception:
public static void premain(final String agentArgs,
final Instrumentation inst) {
System.out.println(
"+++Hey, look: I'm instrumenting a freshly started JVM!");
new AgentBuilder.Default()
.type(ElementMatchers.any())
.transform(new MetricsTransformer())
.with(AgentBuilder.Listener.StreamWriting.toSystemOut())
.with(AgentBuilder.TypeStrategy.Default.REDEFINE)
.installOn(inst);
}
private static class MetricsTransformer implements AgentBuilder.Transformer {
#Override
public DynamicType.Builder<?> transform(
final DynamicType.Builder<?> builder,
final TypeDescription typeDescription,
final ClassLoader classLoader,
final JavaModule module) {
final AsmVisitorWrapper methodsVisitor =
Advice.to(EnterAdvice.class, ExitAdviceMethods.class)
.on(ElementMatchers.isAnnotatedWith(CollectMetrics.class)
.and(ElementMatchers.isMethod()));
final AsmVisitorWrapper constructorsVisitor =
Advice.to(EnterAdvice.class, ExitAdviceConstructors.class)
.on(ElementMatchers.isAnnotatedWith(CollectMetrics.class)
.and(ElementMatchers.isConstructor()));
return builder.visit(methodsVisitor).visit(constructorsVisitor);
}
private static class EnterAdvice {
#Advice.OnMethodEnter
static long enter() {
return System.nanoTime();
}
}
private static class ExitAdviceMethods {
#Advice.OnMethodExit(onThrowable = Throwable.class)
static void exit(#Advice.Origin final Executable executable,
#Advice.Enter final long startTime,
#Advice.Thrown final Throwable throwable) {
final long duration = System.nanoTime() - startTime;
System.out.println(duration);;
}
}
}
byte buddy's versions are 1.9.5, 1.7.11
jdk version: 1.8.0.191
and the Exception in the cmd:
E:\>cd E:\workshop\_android_studio\BounAgent\out\artifacts\BounAgent_jar
E:\BounAgent_jar>java -javaagent:BounAgent.jar -jar untitled.jar
Exception in thread "main" java.lang.NoClassDefFoundError: net/bytebuddy/matcher
/ElementMatcher
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
at java.lang.Class.getDeclaredMethod(Unknown Source)
at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(Unknown Sou
rce)
at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(Unknown So
urce)
Caused by: java.lang.ClassNotFoundException: net.bytebuddy.matcher.ElementMatche
r
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 5 more
FATAL ERROR in native method: processing of -javaagent failed
Thanks in advance.
According to an article I found:
To launch your agent you must bundle the agent classes and resources in a jar, and in the jar manifest set the Agent-Class property to the name of your agent class containing the premain method. (An agent must always be bundled as a jar file, it cannot be specified in an exploded format.)
It appears that your agent JAR file ("BounAgent.jar") does not contain all of the dependencies in the correct form. Specifically, the bytebuddy classes are not in the JAR file. That is causing the agent classes to fail to load.

Basic RMI Example

I am trying out a basic RMI example .But whenever I run the service I get the following error
java.rmi.ConnectException: Connection refused to host: 116.203.202.217; nested exception is:
java.net.ConnectException: Connection timed out: connect
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:601)
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:198)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:184)
at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:322)
at sun.rmi.registry.RegistryImpl_Stub.bind(Unknown Source)
at java.rmi.Naming.bind(Naming.java:111)
at rmi.remote.RemteImpl.main(RemteImpl.java:29)
Here is the code
package rmi.remote;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class RemteImpl extends UnicastRemoteObject implements RemoteIntf{
protected RemteImpl() throws RemoteException {
super();
// TODO Auto-generated constructor stub
}
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public String sayHello() throws RemoteException {
// TODO Auto-generated method stub
return "hi";
}
public static void main(String a[])
{
try {
RemoteIntf service=new RemteImpl();
Naming.bind("Remote",service);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I am using windows 7 OS
Your bind string is incorrect. It should be "rmi://localhost/Remote". And you should also check your 'hosts' file to make sure it maps "localhost" to 127.0.0.1, and your real hostname to your real host address.
It looks like your RMI registry is not running, which is causing the bind call to fail. You are also not binding to a URL but just to a name.
Usually you'd call bind like so:
Naming.bind("//registryHost:port/remote", service);
where registryHost points at the machine that is running your RMI registry.
For a simple local test you'd make the URL "//localhost:port/remote" and run the rmiregistry service on your local machine.
How to do this is explained for example here:
http://www.javacoffeebreak.com/articles/javarmi/javarmi.html
Excerpt:
To start the registry, Windows users should do the following (assuming that your java\bin directory is in the current path):-
start rmiregistry
To start the registry, Unix users should do the following:-
rmiregistry &
public class RemteImpl extends UnicastRemoteObject implements RemoteIntf{
from RemoteInf is a interface which implements Remote, so, in your main code
RemoteIntf service=new RemteImpl(); //avoid this
//priort to adding this also consider to make sure you have initialized security Manager for allowing connection from or all given IP address.
RemoteImpl service = new RemoteImpl();
should be changed to
RemoteInt service = new RemoteImpl();
where a server object is needed. After that , create a server registry in your code if don't want to use rmiregistry.
LocateRegistry.createRegistry(*port*);
finally, bind the service to a url where a rmi service is provided, using
String url = "rmi://127.0.0.1/RemoteObjectRegisteration" ; //or (your remote ip
address on place of 127.0.0.1)
Naming.bind(url, service);
and the server side should be okay. and You should take some time learning how to ask questions in stack overflow.........

play framework scheduler with Akka at server launch

Question 1: I have created a sample java application using play 2.1.1 with a scheduler to be kicked off when the application is started. I did a play compile and then play start, but i'm getting the below error, please let me know if i'm doing anything wrong here:
(Starting server. Type Ctrl+D to exit logs, the server will remain in background)
Play server process ID is 6160
#6edl861on: Cannot init the Global objectOops, cannot start the server.
at play.api.WithDefaultGlobal$$anonfun$play$api$WithDefaultGlobal$$globalInstance$1.apply(Application.scala:57)
at play.api.WithDefaultGlobal$$anonfun$play$api$WithDefaultGlobal$$globalInstance$1.apply(Application.scala:51)
at play.utils.Threads$.withContextClassLoader(Threads.scala:18)
at play.api.WithDefaultGlobal$class.play$api$WithDefaultGlobal$$globalInstance(Application.scala:50)
at play.api.DefaultApplication.play$api$WithDefaultGlobal$$globalInstance$lzycompute(Application.scala:383)
at play.api.DefaultApplication.play$api$WithDefaultGlobal$$globalInstance(Application.scala:383)
at play.api.WithDefaultGlobal$class.global(Application.scala:66)
at play.api.DefaultApplication.global(Application.scala:383)
at play.api.WithDefaultConfiguration$class.play$api$WithDefaultConfiguration$$fullConfiguration(Application.scala:80)
at play.api.DefaultApplication.play$api$WithDefaultConfiguration$$fullConfiguration$lzycompute(Application.scala:383)
at play.api.DefaultApplication.play$api$WithDefaultConfiguration$$fullConfiguration(Application.scala:383)
at play.api.WithDefaultConfiguration$class.configuration(Application.scala:82)
at play.api.DefaultApplication.configuration(Application.scala:383)
at play.api.Application$class.$init$(Application.scala:268)
at play.api.DefaultApplication.<init>(Application.scala:383)
at play.core.StaticApplication.<init>(ApplicationProvider.scala:52)
at play.core.server.NettyServer$.createServer(NettyServer.scala:228)
at play.core.server.NettyServer$$anonfun$main$5.apply(NettyServer.scala:259)
at play.core.server.NettyServer$$anonfun$main$5.apply(NettyServer.scala:258)
at scala.Option.map(Option.scala:145)
at play.core.server.NettyServer$.main(NettyServer.scala:258)
at play.core.server.NettyServer.main(NettyServer.scala)
Caused by: java.lang.RuntimeException: There is no started application
at scala.sys.package$.error(package.scala:27)
at play.api.Play$$anonfun$current$1.apply(Play.scala:46)
at play.api.Play$$anonfun$current$1.apply(Play.scala:46)
at scala.Option.getOrElse(Option.scala:120)
at play.api.Play$.current(Play.scala:46)
at play.api.Play.current(Play.scala)
at play.libs.Akka.system(Akka.java:25)
at Global.<init>(Global.java:27)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at java.lang.Class.newInstance0(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at play.api.WithDefaultGlobal$class.play$api$WithDefaultGlobal$$javaGlobal(Application.scala:30)
at play.api.DefaultApplication.play$api$WithDefaultGlobal$$javaGlobal$lzycompute(Application.scala:383)
at play.api.DefaultApplication.play$api$WithDefaultGlobal$$javaGlobal(Application.scala:383)
at play.api.WithDefaultGlobal$$anonfun$play$api$WithDefaultGlobal$$globalInstance$1.apply(Application.scala:52)
Resources:
Global.java - in apps/
public class Global extends GlobalSettings {
private Logger.ALogger log = Logger.of(Global.class);
private ActorRef myActor = Akka.system().actorOf(
new Props(Retreiver.class));
#Override
public void onStart(Application app) {
log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
Akka.system()
.scheduler()
.schedule(Duration.create(0, TimeUnit.MILLISECONDS),
Duration.create(10, TimeUnit.SECONDS), myActor, "tick",
Akka.system().dispatcher());
}
}
Retreiver.java:
public class Retreiver extends UntypedActor {
private Logger.ALogger log = Logger.of(TweetsRetreiver.class);
#Override
public void onReceive(Object arg0) throws Exception {
// some code here
}
}
application.conf:
application.global=Global
Question 2: Also, No logs are getting printed either in the console or Application.log file. I have used play.Logger package to do the logging, is this the correct package to be used to log in play 2.1.1? Please provide an example for this.
Thanks.
Solved. Problem with the line:
private ActorRef myActor = Akka.system().actorOf(
new Props(Retreiver.class));
When i moved this inside the onStart method, it got triggered correctly. Don't know why i can't define this in class level. Need to check.
For the logging question, you have to use the Play's Logger helper :
#Override
public void onStart(Application app) {
play.Logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
...
}

Obtaining all the methods in a class --- error prone

I am new to reflection and to practice, I downloaded a random Java project from a website. I decided to find out which class has the main method so I wrote the following code:
package reflection;
import java.io.IOException;
import java.lang.reflect.*;
import java.nio.file.*;
public class FindMethods {
public static void main(String[] args) throws IOException{
if(args.length==0){
System.out.println("Exiting");
System.exit(1);
}else{
Path p = Paths.get(args[0]);
DirectoryStream<Path> allClassFiles = Files.newDirectoryStream(p, "*.class");
for(Path each : allClassFiles){
// System.out.println(each.getFileName());
try {
findMethods(each.getFileName().toString());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
public static void findMethods(String file) throws ClassNotFoundException{
System.out.println(file);
Class c = Class.forName(file);
Method[] m = c.getDeclaredMethods();
for(Method each : m){
System.out.println(each.toString());
}
}
}
System.out.println(each.getFileName()); properly returns the .class files in the folder however, it is interspersed with stack trace of ClassNotFoundException
The classes are as follows:
Addwindow$1.class
Addwindow$2.class
Addwindow.class
Authorwindow.class
clsConnection.class
clsSettings$1.class
clsSettings.class
Deletewindow$1.class
Deletewindow$2.class
Deletewindow.class
Editwindow$1.class
Editwindow$2.class
Editwindow.class
Emprptwindow$PrintCommand.class
Emprptwindow.class
Helpwindow.class
LoginFrame$1.class
LoginFrame.class
MainMenu$1.class
MainMenu$2.class
MainMenu.class
Payrptwindow.class
printwindow$1.class
printwindow.class
Settingswindow$1.class
Settingswindow.class
What changes do I need to make to the code to get the methods from each class ?
Stack trace:
java.lang.ClassNotFoundException: Settingswindow
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at reflection.FindMethods.findMethods(FindMethods.java:33)
at reflection.FindMethods.main(FindMethods.java:22)
Random project being talked about:
http://projectseminar.org/java-projects/payroll-accounting-system/98/
.class is part of the filename, but it isn't part of the class name. You need to strip it before passing it to Class.forName.
Another issue is that forName expects packages to be separated using periods, rather than than slashes or whatever directory separator your filesystem uses. If everything is in the default package, this shouldn't be an issue though.
If it's still not working, you should double check the classpath.
Class names that contain a $ are anonymous classes within the outer class (determined by the name to the left of the $). You can safely ignore those in your search for main. Just test for the presence of a $ in the class names in your main loop and skip the processing.
Without knowing more about what app you are looking at, I can't say why your code can't find some of the other classes (like clsConnection).
There is a problem in this approach - you load all project's classes. It is better to analize classes without loading them. There are tools for that. Here's what we can do with http://www.jboss.org/javassist
public static void findMethods(String file) throws Exception {
ClassPool cp = ClassPool.getDefault();
try (InputStream is = new FileInputStream(file)) {
CtClass cc = cp.makeClass(is);
for (CtMethod m : cc.getMethods()) {
System.out.println(m);
}
}
}

ClassLoader with RMI invocation

I trying to make simple java profiler and using ClassLoader for this.
This is my implementation of ClassLoader:
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class CustomClassLoader extends ClassLoader {
private Notifier notifier;
public CustomClassLoader() {
super();
}
public CustomClassLoader(ClassLoader parent) {
super(parent);
}
private void initNotifier() {
if (notifier != null) return;
try {
System.out.println("2");
Registry registry = LocateRegistry.getRegistry(Const.registryPort);
System.out.println("3");
notifier = (Notifier) registry.lookup(Const.stubName);
System.out.println("4");
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
#Override
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
System.out.println("0");
Class clazz = super.loadClass(name, resolve);
System.out.println("1");
initNotifier();
System.out.println("5");
try {
notifier.classLoaded(name);
System.out.println("6");
} catch (RemoteException e) {
e.printStackTrace();
System.exit(1);
}
return clazz;
}
}
When i've try to use this class loader i receive this output (I've tried to use 1.6_37 and 1.7_10 jkd):
C:\Users\Scepion1d>java -cp C:\Users\Scepion1d\Dropbox\Workspace\IntellijIDEA\pr
ofiler\out\artifacts\loader\loader.jar;C:\Users\Scepion1d\Dropbox\Workspace\Inte
llijIDEA\app\out\production\app -Djava.system.class.loader=CustomClassLoader Main
0
1
2
0
1
2
3
0
1
2
3
java.lang.IllegalArgumentException: Non-positive latency: 0
at sun.misc.GC$LatencyRequest.<init>(GC.java:190)
at sun.misc.GC$LatencyRequest.<init>(GC.java:156)
at sun.misc.GC.requestLatency(GC.java:254)
at sun.rmi.transport.DGCClient$EndpointEntry.lookup(DGCClient.java:212)
at sun.rmi.transport.DGCClient.registerRefs(DGCClient.java:120)
at sun.rmi.transport.ConnectionInputStream.registerRefs(ConnectionInputS
tream.java:80)
at sun.rmi.transport.StreamRemoteCall.releaseInputStream(StreamRemoteCal
l.java:138)
at sun.rmi.transport.StreamRemoteCall.done(StreamRemoteCall.java:292)
at sun.rmi.server.UnicastRef.done(UnicastRef.java:431)
at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
at CustomClassLoader.initNotifier(CustomClassLoader.java:22)
at CustomClassLoader.loadClass(CustomClassLoader.java:35)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at sun.security.jca.ProviderConfig$3.run(ProviderConfig.java:234)
at java.security.AccessController.doPrivileged(Native Method)
at sun.security.jca.ProviderConfig.doLoadProvider(ProviderConfig.java:22
5)
at sun.security.jca.ProviderConfig.getProvider(ProviderConfig.java:205)
at sun.security.jca.ProviderList.getProvider(ProviderList.java:215)
at sun.security.jca.ProviderList.getService(ProviderList.java:313)
at sun.security.jca.GetInstance.getInstance(GetInstance.java:140)
at java.security.Security.getImpl(Security.java:659)
at java.security.MessageDigest.getInstance(MessageDigest.java:129)
at java.rmi.dgc.VMID.computeAddressHash(VMID.java:140)
at java.rmi.dgc.VMID.<clinit>(VMID.java:27)
at sun.rmi.transport.DGCClient.<clinit>(DGCClient.java:66)
at sun.rmi.transport.ConnectionInputStream.registerRefs(ConnectionInputS
tream.java:80)
at sun.rmi.transport.StreamRemoteCall.releaseInputStream(StreamRemoteCal
l.java:138)
at sun.rmi.transport.StreamRemoteCall.done(StreamRemoteCall.java:292)
at sun.rmi.server.UnicastRef.done(UnicastRef.java:431)
at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
at CustomClassLoader.initNotifier(CustomClassLoader.java:22)
at CustomClassLoader.loadClass(CustomClassLoader.java:35)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at sun.security.jca.ProviderConfig$3.run(ProviderConfig.java:234)
at java.security.AccessController.doPrivileged(Native Method)
at sun.security.jca.ProviderConfig.doLoadProvider(ProviderConfig.java:22
5)
at sun.security.jca.ProviderConfig.getProvider(ProviderConfig.java:205)
at sun.security.jca.ProviderList.getProvider(ProviderList.java:215)
at sun.security.jca.ProviderList$3.get(ProviderList.java:130)
at sun.security.jca.ProviderList$3.get(ProviderList.java:125)
at java.util.AbstractList$Itr.next(AbstractList.java:345)
at java.security.SecureRandom.getPrngAlgorithm(SecureRandom.java:522)
at java.security.SecureRandom.getDefaultPRNG(SecureRandom.java:165)
at java.security.SecureRandom.<init>(SecureRandom.java:133)
at java.rmi.server.UID.<init>(UID.java:92)
at java.rmi.server.ObjID.<clinit>(ObjID.java:71)
at java.rmi.registry.LocateRegistry.getRegistry(LocateRegistry.java:158)
at java.rmi.registry.LocateRegistry.getRegistry(LocateRegistry.java:106)
at java.rmi.registry.LocateRegistry.getRegistry(LocateRegistry.java:73)
at CustomClassLoader.initNotifier(CustomClassLoader.java:20)
at CustomClassLoader.loadClass(CustomClassLoader.java:35)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
I've thought that problem is in the RMI server, but i wrote another RMI client and it works good.
Does anyone know where is the problem(s) and how to solve it(them)?
TL;DR: Don't use a class loader which such heavy side effects as the root class loader.
The problem is that the const field gcInterval on class sun.rmi.transport.DGCClient is not initialized before it's used (and hence shows value 0). The reason for this is that your class loader makes the call via RMI which creates a new instance of DGCClient. During the execution of the constructor of DGCClient another class is loaded (see stack trace). This third call to the class loader triggers the RMI call again which doesn't create a new instance of DGCClient but uses the previously created one and does some call on it. That means that a call is made on a half-initialized object which leads to the use of this not-yet initialized constant field.
We can't possibly blame Sun/Oracle for this since every Java class can assume that it is loaded without such unpredictable side effects.

Categories