I have an issue with java.io.NotSerializableException at java.io.ObjectOutputStream.writeObject0(Unknown Source). Here is the important part of the code.
public class PlayerConfigAccess implements Serializable{
private static final long serialVersionUID = 1L;
//some load and create methods
public static void saveFile (File file, Player player)
{
Object object = (Object) PlayerConfigContent.getContent(player);
if(!existFile(file))
{
createFile(file);
}
try{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(object);
oos.flush();
oos.close();
PlayerConfigContent.remove(player);
}catch(Exception e){
e.printStackTrace();
}
}
The object I am about to save is a PlayerConfig custom thing, that I convert back to Object.
The method gets the file that should be saved when its called, I made sure it exists, so there cant be the problem.
Does someone know who I can fix this issue. Thanks :)
The object that you're actually writing needs to be serializable, not the class that is actually holds the writing code. What object type does PlayerConfigContent.getContent return?
Related
I want to load and render multiple objects to a gameworld using data from a class with a save/load functionality using (de)serialization, but i cant figure out how to properly reintroduce them to the program since they contain transient objects that are nessesary to render/display them.
The first time i run my program, it tries to load data from a txt file called 'Data.txt' that doesnt exist. The program creates a new Data.txt file, adds a Campfire object called 'campfire'to it and saves it. As long as the program runs it will be rendered to the screen (this part works fine). After closing the program and restarting it its supposed to check for the file, find it and load the ArrayList 'data' with the previously saved/serialized campfire object from it. Then it adds another Object of the same type to it and renders both of them. This part throws a NullPointerException in the render method of my Campfire class.
This is the Main class:
public class MainClass extends ApplicationAdapter{
public static SpriteBatch batch;
private Data data;
private Campfire campfire;
#Override
public void create () {
batch = new SpriteBatch();
data = new Data();
data.load();
campfire = new Campfire();
data.addCampfire(campfire);
System.out.println(data.getSize());
data.save();
}
#Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
data.render(batch);
batch.end();
}
The class that loads all the files:
public class Data {
private String filename;
private ArrayList<Campfire> data;
public Data() {
data = new ArrayList<Campfire>();
filename = "Data.txt";
}
public void save(){
try {
FileOutputStream file = new FileOutputStream (filename);
ObjectOutputStream out = new ObjectOutputStream (file);
out.writeObject(data);
out.close();
file.close();
}catch (IOException e) {e.printStackTrace();}
}
public void load() {
try {
FileInputStream file = new FileInputStream (filename);
ObjectInputStream in = new ObjectInputStream(file);
data = (ArrayList<Campfire>)in.readObject();
in.close();
file.close();
}
catch (IOException io) {System.out.println("File not found.");}
catch (ClassNotFoundException ex) {System.out.println("Cant load from file.");}
}
public void addCampfire(Campfire object) {
data.add(object);
}
public void render(SpriteBatch batch) {
for(int i = 0;i < data.size(); i++) {
Campfire camp = data.get(i);
camp.render(batch);
//data.get(i).render(batch);
}
}
public Campfire get(int index) {
return data.get(index);
}
public void set(int index, Campfire object) {
data.set(index, object);
}
public int getSize() {
return data.size();
}
And this is the class that throws the NullPointerException in render():
public class Campfire implements Serializable{
private transient Texture img;
private int id;
public Campfire() {
img = new Texture("campfire.png");
}
public void render(SpriteBatch batch) {
batch.draw(img, 200,200, 2000,2000);
}
The reason for this is that the Texture 'img' is nonexistent since i need to use the transient keyword with it and therefore it will not be saved/loaded to/from the data file.
i need a different way to create objects based on the array list i am loading from. I cant work with the objects in the arrayList because they cant be rendered (the transient keyword has to be assigned to the Texture() object - its not serializable). I have watched plenty of tutorials and read a good amount on articles about this topic, but i cant find one that mentions how i can reintroduce the object so i can make use of its functions that rely on not (de)serializable parts of it.
So heres my question:
Is there a better way than my attempt (creating the object again and then assigning the deserialized values to it? I have no clue how to properly load and work with the 'data' ArrayList after the deserialization process and i am thankful for every advice on how to reintroduce them to the program.
Thanks in advance,
M
I would recommend not using java serialization for this. It can have advantages in terms of the size of its serialized format, but in my experience it is a little bit of a pain to work with. You have encountered this pain, because you cannot serialize that Texture object because it is not Serializable. You avoided the issue by marking it as transient, which is a mistake. There are probably workarounds for working with objects that you do not own - registering some handler, but tbh I do not know the details because I avoid it.
Instead, go for a nice friendly format like json. This will mean that your serialized data file will be a bit bigger, but, you can open it up and read it and see what you have saved.
And... libgdx comes with some tools for it. See their wiki page on usage here
There are alternatives - like googles gson library as well, but why not just stick with libgdx's tools - I have found them to be pretty solid.
Just an extra warning - if you are using some sort of code obfuscation/minimization tool in Android, you will need to configure that to not rename any object that you serialize, because it does rely on the package and object names for deserialization. It is also something to be aware of if you save a game state - then change the names/packages of your objects and then try to load that game state.
I have to save and load a chess game. In Chess I have:
public class Chess
{
private Piece[][] pieceArray;
private Board board;
private int moves;
private boolean turn;
...
Set's and get's
}
I would have to load the turn, moves and the matrix. For now Im only saving and loading the matrix (Pieces[][])
Now I have these methods for saving and loading the game in another class
In this class I have a FTPClient connected to a server.
Saving the game:
public boolean saveGame(Chess chess) {
boolean error = false;
try {
File file = new File("game.save");
FileOutputStream fis = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fis);
oos.writeObject(chess.getArray());
oos.close();
// Save that file in the server
FileInputStream fis = new FileInputStream(new File("game.save"));
client.storeFile("game.save", fis);
fis.close();
file.delete();
} catch (IOException e) {
e.printStackTrace();
}
return error;
Saving the game gives me no problem and goes smoothly.
And now this is the method I use to load the game, which is the one throwing the invalidClassException.
try {
FileInputStream fis = new FileInputStream(new File("game.save"));
ObjectInputStream ois = new ObjectInputStream(fis);
chess.setArray((Piece[][]) ois.readObject());
chess.paintInBoard();
ois.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
Whenever I try to read the matriz I get "java.io.InvalidClassException: [LPiece;; invalid descriptor for field "
I have implemented the Serializable interface in Piece and Chess.
I have tried saving the whole Chess class but doing that I would have to implement the Serializable interface in other 8 classes as well and I'm trying to avoid that.
Do I have to read each Piece individually?
Thank you a lot.
It is hard to determine what the problem might be because the Piece interface nor its implementing classes are not provided, but here are my thoughts on this problem:
I personally would avoid saving an array or a matrix. I would instead save the pieces in a container class, for example: PieceCollection.
I can't see any specific problem with your provided code (unless chess.getArray() returns something else than pieceArray).
I believe that the main problem here is that the ObjectInputStream can't distinguish the various implementations of Piece. I would suggest that you try to add serialVersionUID to the implementing Piece classes. For more information, see the following link: https://docs.oracle.com/javase/7/docs/platform/serialization/spec/class.html
The Piece classes are missing a no-arg constructor. See the following link for more information: https://docs.oracle.com/javase/8/docs/api/index.html?java/io/InvalidClassException.html
Good luck! I hope that this answer will help you.
I tried saving the saves locally and it worked. The problem was that the server I was using corrupted the file every time I uploaded it, giving me that exception. Changing the server did the job.
I had a programming assignment where i had to save separate files, one a log file and the other a dat file. Each one took an arraylist object and saved it in the file but each arraylist was different. I was under a time crunch so i ended up making separate functions for both but i'm wondering if there's a more modular way of doing it. So for example:
public void saveLog (ArrayList<A> objectArray, File fileName) throws IOException {
if (!fileName.exists()) {
logFile.createNewFile();
}
FileOutputStream fileoutput = new FileOutputStream(fileName);
ObjectOutputStream output = new ObjectOutputStream(fileoutput);
output.writeObject(objectArray);
output.close();
fileoutput.close();
}
Is there a way to recode this so it will also take ArrayList"<"B">" ? I tried using ArrayList"<"Object">" but that threw an error. Very new to java so sorry if this seems like a simple question.
Basically you need to accept an ArrayList which contains objects that can be serialized, this can easily be expressed with a wildcard, eg:
public void saveLog(ArrayList<? extends Serializable> objectArray, File fileName) {
..
}
Which means "accept an ArrayList of an unspecified type which implements Serializable interface", which is a requirement for the ObjectOutputStream.
You could make the method generic on A (and I would prefer the List interface). Also, I would prefer a try-with-resources Statement. Like
public <A> void saveLog(List<A> objectArray, File fileName)
throws IOException {
if (!fileName.exists()) {
logFile.createNewFile();
}
try (FileOutputStream fileoutput = new FileOutputStream(fileName);
ObjectOutputStream output = new ObjectOutputStream(fileoutput)) {
output.writeObject(objectArray);
}
}
just started using the Serializable-thingy, I want to save a couple of lists and some other objects, but I can't seem to get some things right.
I have some JLists with their own "DefaultListModel" that I use to sort things in the list, I call the class SortModel, when I run the program I do this:
SortModel sortModel = new SortModel();
JList jList = new JList(sortModel);
Then later when the program runs, objects are added and sorted according to the specified needs, now, when I save the lists and load them again, they're empty.
I also save a object of a class that holds the background for the program (user chooses one themself), after saving it I need to add it again to the program (the object, background is stored in it), I need to add it to the program again not only load it "as it where", plus I have some objects that I added on that object with their own listeners. After I somehow succeeded in loading it, the objects are there but I can't use them, so I figure listeners don't get saved?
* explaining edit
The class that is the program extends JFrame, nothing funny about that I think.
The "background obect" (call it map) extends JComponent, I add this to (let's call it program for now...) the program and it pops up with the image which it holds. Onto this map I then add objects that also extends JComponent (call them dots), the dots are assigned their own listeners before they're added, the listeners might not be "real" listeners, but they act the same way, they're "MouseAdapter" does that makes any difference?.
/explaining edit *
* code edit *
code for saving:
FileOutputStream fOut = new FileOutputStream("testFile.mpd");
ObjectOutputStream outSt = new ObjectOutputStream(fOut);
outSt.writeObject(savedMap);
"testFile.mpd" is what it sounds like, I'm quite sure the .mpd shouldn't matter, you can make up your own formats, right? :) (main-class is called Mappedoodle, .mpd sounds reasonable, no?)
"savedMap" is an object of said Mappedoodle and holds all lists and other information needed to be saved.
code for loading:
FileInputStream fIn = new FileInputStream("testFile.mpd");
ObjectInputStream inSt = new ObjectInputStream(fIn);
Mappedoodle openedMap = (Mappedoodle)inSt.readObject();
The information in openedMap is used (well... it should be...) to overwrite certain things in the program.
* /code edit *
Adding everything back onto this object, even adding everything back into the lists wouldn't be so hard since that's just some more lists and a few loops, but I feel like I just don't really get Serializable ^^ so, someone care to try to explain why not everything gets saved? And if it is, why I can't access it? But if I can, how? :)
I don't know what more code should be relevant, please tell me what more information you would need to help me solve this, pasting the whole program would be really messy since it's 11 classes and quite a few lines.
Thanks <3
The code you must show us must be sufficient to demonstrate your error, and I unfortunately must state that yours doesn't. For instance if I use your code in a very simple example (something I recommend that you do), you'll see that it works. My test code:
Mappedoodle.java
import java.io.Serializable;
public class Mappedoodle implements Serializable {
private static final long serialVersionUID = -1760231235147491826L;
private String text;
private int value;
public Mappedoodle(String text, int value) {
this.text = text;
this.value = value;
}
public String getText() {
return text;
}
public int getValue() {
return value;
}
#Override
public String toString() {
return text + ", " + value;
}
}
MappedoodleSerialize.java
import java.io.*;
public class MappedoodleSerialize {
public static void main(String[] args) {
Mappedoodle savedMap = new Mappedoodle("Fubar", 200);
FileOutputStream fOut;
try {
// your code below
fOut = new FileOutputStream("testFile.mpd");
ObjectOutputStream outSt = new ObjectOutputStream(fOut);
outSt.writeObject(savedMap);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
MappedoodleDeSerialize.java
import java.io.*;
public class MappedoodleDeSerialize {
public static void main(String[] args) {
try {
// your code below
FileInputStream fIn = new FileInputStream("testFile.mpd");
ObjectInputStream inSt = new ObjectInputStream(fIn);
Mappedoodle openedMap = (Mappedoodle) inSt.readObject();
System.out.println(openedMap);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
}
}
}
This bit of code compiles, runs and outputs as expected. Your error must lie in code that you've not shown us.
This problem was solved 5 years ago, the solution is lost due to bad memory though.
I did some reading on the API for File IO and read the following blog post: http://techknock.blogspot.com/2008/05/file-hadling-in-android.html. His code works fine when everything is in the same activity. But what I am trying to do is create an IOInterface class that I can use to open multiple databases to populate multiple lists.
ListA.java
public class ListA
{
public List<ClassA> list;
private final String DBA = "dbA";
private IOInterface database;
public List()
{
list = new ArrayList<ClassA>();
database = new IOInterface();
}
...
public void initListA() throws IOException
{
database.openForWriting(DBA);
String myStr = new String("content");
database.dos.writeBytes(myStr);
database.dos.flush();
database.dos.close();
}
}
IOInterface.java
public class IOInterface
{
public DataOutputStream dos;
private FileOutputStream fos;
public void openForWriting(String database)
{
try {
fos = openFileOutput(database, Content.MODE_PRIVATE);
dos = new DataOutputStream(fos);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
Eclipse underlines fos = openFileOutput(database, Content.MODE_PRIVATE);. With the comment that openFileOutput() does not exist. The resolution to this is to extend the IOInteface class as an Activity. I suppose then openFileOutput() is a method of an activity class.
So my question is how do accomplish what I am trying to do? Standard Java file io such as:
File fp = new File("database");
FileOutputStream fos = new FileOutputStream(fp);
does not work. It catches a FileNotFoundException. This has to be doable though. Any ideas?
Thanks,
Method openFileOutput() is contained in the Context class, so you can pass an instance of this class to your method that opens files. And you should always use methods from Context when you want to work with files.
You can read about using the internal and external storages in the development guide.