Hello. I'm writing an RMI application for my semester project, and I'm getting a really frustrating error! I have the interface PlugNPlayIMPL that contains 5 or so abstract methods. One method (init) is called and it creates a new JPanel in the class that was bond to the registry. Here's the problem: I'm trying to paint to the panel, but when I call <JPanel>.getGraphics(), it throws a null pointer exception. I'm checking beforehand to make sure that the JPanel has been created too... Does anyone have a solution/explanation?

Recommended Answers

All 8 Replies

Hello,

Please post the code related to the problem so we can check and help you on it.

Still...

You are using JPanel.getGraphics() to get the Graphics object to draw on. You should be drawing only within the paintComponent() method using the graphics object supplied as the argument.

Hope this can help you.

Regards,

DUH!! wow, I hate it when I make stupid mistakes like that. I'm usually pretty good about overriding the paintComponent method.

I don't have the code right now (It's at school), but I think that should solve the problem. Thanks a lot!

Okay, but when I override paintComponent, it gives me an error...

It works if I don't override paintComponent (as in it doesn't throw any errors, but nothing is painted...)... why's that?

Code (The class that is having problems, the other class calls init and start game)

package server;

import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;
import game.*;

import javax.swing.*;
import java.awt.*;


/**
 * Write a description of class Linker here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class TestGame implements PlugNPlayIMPL{

    JPanel gamePanel;

    public TestGame(){
        init();
    }
    
    public void startGame(){
        gamePanel = new JPanel();
        while(true){
            gamePanel.repaint();
        }
    }
    
    public void endGame(){}
    
    public void testPaint(Graphics g){
        if(g==null) {
            System.out.println("THESE GRAPHICS HATE YOU AND YOUR FAMILY!!!");
            return;
        }
        g.fillRect(35,35,200,200);
    }
    
    public void init(){
        gamePanel = new JPanel(){
            public void paintComponent(Graphics g){
                super.paintComponent(g);
                testPaint(g);
            }
        };
    }
    
    public static void main(String[] args){
        try{
            Runtime.getRuntime().exec("rmiregistry", null, new java.io.File("I:\\RMI_Server"));
            
            PlugNPlayIMPL game = new TestGame();
            PlugNPlayIMPL stub = (PlugNPlayIMPL) UnicastRemoteObject.exportObject(game, 0);
            Registry reg = LocateRegistry.getRegistry();
            reg.rebind("TestGame", stub);
            System.out.println("Bound Game Object.");
            
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    
    public void loadSplashScreen(){}
    
    public JPanel getGamePanel() throws RemoteException{ return gamePanel; }
}

Error:

java.lang.ClassCastException: cannot assign instance of $Proxy1 to field server.TestGame$1.this$0 of type server.TestGame in instance of server.TestGame$1
at java.io.ObjectStreamClass$FieldReflector.setObjFieldValues(ObjectStreamClass.java:2032)
at java.io.ObjectStreamClass.setObjFieldValues(ObjectStreamClass.java:1212)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1953)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:306)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:155)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:178)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:132)
at $Proxy1.getGamePanel(Unknown Source)
at client.LoadGame.main(LoadGame.java:32)
at client.__SHELL3.run(__SHELL3.java:6)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at bluej.runtime.ExecServer$3.run(ExecServer.java:855)

Okay, but when I override paintComponent, it gives me an error...

It works if I don't override paintComponent (as in it doesn't throw any errors, but nothing is painted...)... why's that?

Code (The class that is having problems, the other class calls init and start game)

package server;

import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;
import game.*;

import javax.swing.*;
import java.awt.*;


/**
 * Write a description of class Linker here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class TestGame implements PlugNPlayIMPL{

    JPanel gamePanel;

    public TestGame(){
        init();
    }
    
    public void startGame(){
        gamePanel = new JPanel();
        while(true){
            gamePanel.repaint();
        }
    }
    
    public void endGame(){}
    
    public void testPaint(Graphics g){
        if(g==null) {
            System.out.println("THESE GRAPHICS HATE YOU AND YOUR FAMILY!!!");
            return;
        }
        g.fillRect(35,35,200,200);
    }
    
    public void init(){
        gamePanel = new JPanel(){
            public void paintComponent(Graphics g){
                super.paintComponent(g);
                testPaint(g);
            }
        };
    }
    
    public static void main(String[] args){
        try{
            Runtime.getRuntime().exec("rmiregistry", null, new java.io.File("I:\\RMI_Server"));
            
            PlugNPlayIMPL game = new TestGame();
            PlugNPlayIMPL stub = (PlugNPlayIMPL) UnicastRemoteObject.exportObject(game, 0);
            Registry reg = LocateRegistry.getRegistry();
            reg.rebind("TestGame", stub);
            System.out.println("Bound Game Object.");
            
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    
    public void loadSplashScreen(){}
    
    public JPanel getGamePanel() throws RemoteException{ return gamePanel; }
}

Error:

java.lang.ClassCastException: cannot assign instance of $Proxy1 to field server.TestGame$1.this$0 of type server.TestGame in instance of server.TestGame$1
at java.io.ObjectStreamClass$FieldReflector.setObjFieldValues(ObjectStreamClass.java:2032)
at java.io.ObjectStreamClass.setObjFieldValues(ObjectStreamClass.java:1212)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1953)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:306)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:155)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:178)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:132)
at $Proxy1.getGamePanel(Unknown Source)
at client.LoadGame.main(LoadGame.java:32)
at client.__SHELL3.run(__SHELL3.java:6)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at bluej.runtime.ExecServer$3.run(ExecServer.java:855)

Well, Im not sure too.

Try to declare testPaint() method inside the JPanel anonymous class OR create another class that extends JPanel and override paintComponent() method.

Create object of that class instead of JPanel.

Let me know if it works or not.

Regards,

@llemes

Is this regarding the game project you were talking about? If yes, then this approach seems kinda wrong. AFAIK, in case of network games, the graphics are *never* rendered at the server and transferred to the client. The server doesn't dictate what has to be displayed but rather how things have to be displayed.

Let's take an example of a MMORPG. The way it is normally done is that when the user is first distributed a jar which already contains the view related resources i.e. images, sound files, map data etc. When the user starts the game the map on which the user is supposed to be is rendered using the local map file. But the state of the other entities like monsters, treasures etc. are pulled from the server using RMI or a custom efficient protocol. Such world updates are pushed to the client continuously and the actions by both the gamer and the other users affect the state of the visible/invisible world. In practice, there is a *lot* which goes behind the scene to make this all *work*. And given that all that I have presented till now is pure speculation/guesswork of how things should work, you need to do a bit of research by reading the code of other open source network games out there.

Of course, you can do away with the client requiring to download your JAR file by using an applet and making the browser download your latest game jars every time a game is requested.

Are you sure that your project requires you to download a game *instance* using RMI?

You download the JAR from the server through a socket, and then when you run the jar, you grab the Panel that has the graphics and paints it to the client screen.......

Okay. This has nothing to do with my JISO project (If that's what you were refering to). This is more of a Steam-like application. For my programming class, the second years are making a plug-n-play game system. I've been placed in charge on the networking, and I want it to run as smooth as possible, lol.

I thought it would work best if the user could go and download each game (They're basic Arcade Games, they only multiplayer feature is the scoreboard). I thought that each game's graphics should be rendered to a GamePanel which extends JPanel and handles the RMI and painting, so the people writing adition games don't have to deal with it.

Correct me if I'm wrong, but I was under the impression that RMI provided a refrence to the object uploaded to the RMIRegistry, and it was used directly by the client. If that's true, then the graphics painted on the server side (The Classes that render the GamePanel in the JAR file) should appear on the client side as well. The guides that I found didn't go into great detail how exactly this worked, and that's how I interperated it...

Also: This is my latest error, it's getting smaller =P
java.lang.ClassCastException: $Proxy1
at $Proxy1.getGamePanel(Unknown Source)
at client.LoadGame.main(LoadGame.java:29)
at client.__SHELL19.run(__SHELL19.java:6)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at bluej.runtime.ExecServer$3.run(ExecServer.java:855)

GamePanel class so far:

package game;

import java.awt.Graphics;
import javax.swing.JPanel;

public abstract class GamePanel extends JPanel{

    private static final long serialVersionUID = 663246266261241246L;

    public GamePanel(){ 
        super();
    }
    
    @Override
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        this.requestFocusInWindow();
        g = paintPanel(g);
    }
    
    protected abstract Graphics paintPanel(Graphics g);
    
}

and the PlugNPlayIMPL:

package game;

import java.rmi.*;
import java.util.HashMap;
import javax.swing.*;

/**
 * Interface class that extends the Remote interface.  Contains methods that ALL
 * PlugNPlay games will have.  However, only 1 or 2 are required to override.  
 * The PlugNPlay class takes care of the rest.
 * 
 * @author (Neil Semmel) 
 * @version (Version 1.0.1 - Aug 26, 2009)
 */

public interface PlugNPlayIMPL extends Remote{

    /**
     * Get the JPanel that contains the game.
     * @return The JPanel object that has the game on it.
     */
    public abstract GamePanel getGamePanel() throws RemoteException;
    /**
     * Load the games Splash Screen (Implemented by the class that extends PlugNPlay).
     * Does nothing if the subclass of PlugNPlay does not override the method.
     */
    public abstract void loadSplashScreen() throws RemoteException;
    /**
     * Start the game animation.  Implemented in subclass of PlugNPlay.
     */
    public abstract void startGame() throws RemoteException;
    /**
     * End the game animation.  Implemented in subclass of PlugNPlay.
     */
    public abstract void endGame() throws RemoteException;
    /**
     * Load all the game resources, and ready the game for playing.
     */
    public abstract void init() throws RemoteException;
}

Note that the methods from the interface that are not overridden in the GamePanel class must be overriden in it's subclass.

>This has nothing to do with my JISO project (If that's what you were
> refering to)

No, I was referring to your school project which you had mentioned in an earlier thread.

>If that's true, then the graphics painted on the server side (The
>Classes that render the GamePanel in the JAR file) should appear
>on the client side as well.

That's like saying that when I hit a web server, I need to see the HTML page displayed at the server. Re-read my previous post in which I point out which things are normally placed at the server and which things are placed at the client. RMI stands for "Remote method invocation", you use remoting capabilities to invoke a method and the proxy generated gives the client an illusion of local method calls. I'd suggest reading a bit or at least understanding the architecture/rationale behind RMI before using it for a full blown project like this.

Okay, sorry, I think it's starting to make sense now. Somehow (I don't know how), the server has to tell the client what to draw. So, now I have to come up with some sort of system that allows the server to pass instructions to the client to get it to draw, right?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.