David Pace
David Pace

Reputation: 25

Invalid Class Exception: No valid constructor

This is odd, the class works fine until after logging out of the game but when logging back in it sends the exception.

Here's the child class

    package com.rs.game.player.quests.impl;

import java.io.Serializable;

import com.rs.game.player.Player;
import com.rs.game.player.dialogues.Dialogue;
import com.rs.game.player.quests.Quest;

/**
 * Handles the cooks assistant quest.
 * 
 * @author Thomas Le Godais <[email protected]>
 *
 */
@SuppressWarnings("serial")
public class CooksAssistant extends Quest<CooksAssistant.Stage, CooksAssistant.Nodes> implements Serializable {

    /**
     * The current nodes of the quest.
     * 
     * @author Thomas Le Godais <[email protected]>
     *
     */
    public enum Nodes {
        /*
         * The chef node.
         */
        CHEF(false);


        /** The interaction value. **/
        private boolean value;

        /**
         * Constructs a new Nodes instance.
         * 
         * @param value the value.
         */
        private Nodes(boolean value) {
            this.value = value;
        }

        /**
         * Gets the value of the node.
         * 
         * @return the value.
         */
        public boolean getValue() {
            return value;
        }

        /**
         * Sets the value of the node.
         * 
         * @param newValue the new value to set.
         */
        public void setValue(boolean newValue) {
            this.value = newValue;
        }
    }

    /**
     * The different stages of the quest.
     * 
     * @author Thomas Le Godais <[email protected]>
     *
     */
    public enum Stage {
        /*
         * Start the quest.
         */
        START,

        /*
         * Gather the ingredients.
         */
        GATHER_INGREDIENTS, 

        /*
         * The talk to chef.
         */
        TALK_TO_CHEF, 

        /*
         * Finish the quest.
         */
        FINISH

    }


    private Player player;

    /**
     * Constructs a new CooksAssistant instance.
     */
    public CooksAssistant(Player player) {
        super("Cooks' Assistant", 1, Stage.START, Nodes.CHEF);
        this.player = player;
    }


    @Override
    public void handleQuest() {
        switch(getQuestState()) {
        case START:
            player.getPackets().sendRunScript(1207, new Object[] { 5 });    
            player.getInterfaceManager().sendInterface(275);

            for(int i = 0; i < 21; i++)
                player.getPackets().sendIComponentText(275, i, "");

            player.getPackets().sendIComponentText(275, 1, this.getName());
            player.getPackets().sendIComponentText(275, 10, "Begin by speaking with the Cook in Lumbridge Castle.");

            player.getPackets().sendIComponentText(275, 12, "Requirments:");
            player.getPackets().sendIComponentText(275, 13, "<str>None.</str>");
            break;

        case GATHER_INGREDIENTS:
            player.getPackets().sendRunScript(1207, new Object[] { 5 });    
            player.getInterfaceManager().sendInterface(275);

            for(int i = 0; i < 21; i++)
                player.getPackets().sendIComponentText(275, i, "");

            player.getPackets().sendIComponentText(275, 1, this.getName());
            player.getPackets().sendIComponentText(275, 10, "You need the following requirements");

            player.getPackets().sendIComponentText(275, 12, "Requirments:");
            player.getPackets().sendIComponentText(275, 13, "Eggs");
            player.getPackets().sendIComponentText(275, 14, "Milk");
            player.getPackets().sendIComponentText(275, 15, "Flour");
            break;

        case TALK_TO_CHEF:

            break;

        case FINISH:

            break;
        }
    }


    @Override
    public void handleDialogue(int npcId) {
        switch(npcId) {
        case 847:
            player.getDialogueManager().startDialogue(new Dialogue() {

                private int npcId;

                @Override
                public void start() {                   
                    npcId = 847;

                    if(hasInteracted(Nodes.CHEF))
                        sendNPCDialogue(npcId, 9827, "Have you gathered my ingredients?.");
                    else
                        sendNPCDialogue(npcId, 9827, "Waahh, what am I to do? I'm so done for!!");
                }

                @Override
                public void run(int interfaceId, int componentId) {
                    if (!(hasInteracted(Nodes.CHEF))) {
                        switch (stage) {
                        case -1:
                            this.sendOptionsDialogue("What would you like?", new String[] { "What's wrong, chef?", "Grow up, you big baby!", "Nevermind, I'll leave you alone." });
                            stage = 0;
                            break;
                        case 0:
                            if (componentId == OPTION_1) {
                                sendPlayerDialogue(9827, "What's wrong, chef?");
                                stage = 1;
                            } else if (componentId == OPTION_2) {
                                sendPlayerDialogue(9827, "Grow up, you big baby!");
                                stage = 15;
                            } else if (componentId == OPTION_3) {
                                sendPlayerDialogue(9827, "Nevermind, I'll leave you alone.");
                                stage = 15;
                            }
                            break;
                            /*
                             * I need some ingredients for the kings birthday cake.
                             */
                        case 1:
                            sendNPCDialogue(npcId, 9827, "I need some ingredients for the kings birthday cake, and I do not have enough time to go get them myself.");
                            stage = 2;
                            break;
                            /*
                             * What do you need?
                             */
                        case 2:
                            sendPlayerDialogue(9827, "Well maybe I could be of assistance, what do you need?");
                            stage = 3;
                            break;
                            /*
                             * I need milk, eggs, and flour.
                             */
                        case 3:
                            sendNPCDialogue(npcId, 9827, "Well I have the frosting, so I guess that just leaves milk, eggs, and flour. Do you think you could help me out, there will be a small reward.");
                            stage = 4;
                            break;
                            /*
                             * That shouldn't be too hard to get.
                             */
                        case 4:
                            sendPlayerDialogue(9827, "That shouldn't be too hard for me to gather, I'll be back in a jiffy!");
                            stage = 5;
                            break;
                            /*
                             * Oh my god, that you so much.
                             */
                        case 5:
                            sendNPCDialogue(npcId, 9827, "Thank you so much, " + player.getUsername() + ", I owe you big time!");
                            setQuestState(Stage.GATHER_INGREDIENTS);
                            for(Nodes node : Nodes.values()) {
                                if(node.equals(Nodes.CHEF)) {
                                    node.setValue(true);
                                    stage = 15;
                                }
                            }
                            break;
                            /*
                             * This is where we end the current dialogue.
                             */
                        case 15:
                            end();
                            break;
                        }
                    } else {
                        switch(stage) {
                        case -1:
                            break;
                        }
                    }
                }

                @Override
                public void finish() {                  
                }
            });
            break;
        }
    }


    @Override
    public void handleObjectClick(int objectId, boolean firstClick, boolean secondClick, boolean thirdClick) {      
        if(firstClick) {
            switch(objectId) {

            }
            return;
        } else if(secondClick) {
            switch(objectId) {

            }
            return;
        } else if(thirdClick) {
            switch(objectId) {

            }
            return;
        }
    }


    @Override
    public boolean hasDialogue() {
        return true;
    }


    @Override
    public boolean hasObjectClick() {
        return false;
    }


    @Override
    public boolean hasInteracted(Nodes node) {
        if(node.getValue() == true)
            return true;
        return false;
    }
    }

Here's the parent

    package com.rs.game.player.quests;

/**
 * Represents a single quest of the Rune-Force server.
 * 
 * @author Thomas Le Godais <[email protected]>
 * @param T
 *      An enumeration that is used to handle quest states.
 * @param E
 *      An enumeration that is used to handle interaction.
 */
public abstract class Quest<T extends Enum<T>, E extends Enum<E>> {

    /** The name of the quest. **/
    private String name;

    /** The id of the quest **/
    private int questId;

    /** The state of the quest to handle. **/
    private T questState;

    /** The node interaction. **/
    private E nodeInteraction;

    /**
     * Constructs a new AbstractQuest instance.
     * 
     * @param name The name of the quest.
     * @param questId The id of the quest.
     * @param questState The state of the quest.
     */
    public Quest(String name, int questId, T questState, E nodeInteraction) {
        this.name = name;
        this.questId = questId;
        this.questState = questState;
        this.nodeInteraction = nodeInteraction;
    }

    /**
     * Handles an quest.
     * 
     * @param player The player to handle the quest.
     */
    public abstract void handleQuest();

    /**
     * Handles the dialogue of the quest.
     * 
     * @param player the player interacting with the npc.
     * @param npcId the npc interacting with the player.
     */
    public abstract void handleDialogue(int npcId);

    /**
     * Handles object clicks.
     * 
     * @param player the player clicking objects.
     * @param objectId the object id.
     * @param firstClick the first click.
     * @param secondClick the second click.
     * @param thirdClick the third click.
     */
    public abstract void handleObjectClick(int objectId, boolean firstClick, boolean secondClick, boolean thirdClick);

    /**
     * Does the quest contain dialogue?
     * 
     * @return True, if it does.
     */
    public abstract boolean hasDialogue();

    /**
     * Does the quest contain object click?
     * 
     * @return True, if it does.
     */
    public abstract boolean hasObjectClick();

    /**
     * Checks if a player has interacted with a node.
     * 
     * @param node the node to interact.
     * @return has interacted or not.
     */
    public abstract boolean hasInteracted(E node);

    /**
     * Gets the current state of the quest.
     * 
     * @return The current state.
     */
    public T getQuestState() {
        return questState;
    }

    /**
     * Sets the current state of the quest.
     * 
     * @param questState The state of the quest.
     */
    public void setQuestState(T questState) {
        this.questState = questState;
    }

    /**
     * Gets the id of the quest.
     * 
     * @return The quest id.
     */
    public int getQuestId() {
        return questId;
    }

    /**
     * Gets the name of the quest.
     *
     * @return The name of the quest.
     */
    public String getName() {
        return name;
    }

    /**
     * Gets the node interaction.
     * 
     * @return the interaction.
     */
    public E getNodeInteraction() {
        return nodeInteraction;
    }

    /**
     * Sets the node interaction.
     * 
     * @param nodeInteraction the interaction to set.
     */
    public void setNodeInteraction(E nodeInteraction) {
        this.nodeInteraction = nodeInteraction;
    }
}

Here's the exception

java.io.InvalidClassException: com.rs.game.player.quests.impl.CooksAssistant; no valid constructor
    at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(Unknown Source)
    at java.io.ObjectStreamClass.checkDeserialize(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at java.util.HashMap.readObject(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

Can someone help me solve this?

Upvotes: 1

Views: 2180

Answers (1)

Reimeus
Reimeus

Reputation: 159754

Read the contract for Serializable

During deserialization, the fields of non-serializable classes will be initialized using the public or protected no-arg constructor of the class. A no-arg constructor must be accessible to the subclass that is serializable.

CooksAssistant should have a no-args constructor for Serialization

public CooksAssistant() {
   super("Cooks' Assistant", 1, Stage.START, Nodes.CHEF);
}

As player is already a field it should be serialized correctly if set at the time of serialization

Upvotes: 2

Related Questions