I'm implementing serialization, and am trying to make everything as modular as possible. When reading objects from files, I'm trying to use just one function to pass everything to an ArrayList, or something of that sort. Currently I'm doing something like this:
public static ArrayList<Class1> ReadClass1(String fileName) {
ArrayList p = null;
try {
ObjectInputStream in = new ObjectInputStream(
new BufferedInputStream(
new FileInputStream(fileName)));
p = new ArrayList<Class1>();
while (1 != 2) {
p.add((Class1) in.readObject());
}
} catch (Exception e) {
;
}
return p;
}
However, I want to read other classes, let's say Class2 or Class3, and right now I'm copy-pasting the code and just editing everything that says "Class1" to "Class2". Is there a way to pass in a specific type I want to use, like this?
public static ArrayList<myClass> ReadProducts(String fileName, myClass) { //where myClass is a class
ArrayList p = null;
try {
ObjectInputStream in = new ObjectInputStream(
new BufferedInputStream(
new FileInputStream(fileName)));
p = new ArrayList<myClass>();
while (1 != 2) {
p.add((myClass) in.readObject());
}
} catch (Exception e) {
;
}
return p;
}
So that I could reuse the function for different classes?
You can use java Generics. Please find the code below:
public static <T> ArrayList<T> ReadProducts(String fileName, Class<T> t) {
ArrayList p = null;
try {
ObjectInputStream in = new ObjectInputStream(
new BufferedInputStream(
new FileInputStream(fileName)));
p = new ArrayList<T>();
while (1 != 2) {
p.add(t.cast(in.readObject()));
}
} catch (Exception e) {
;
}
return p;
}
Related
#Override
public Collection<Flight> getAll() {
try (ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)))) {
Object read = ois.readObject();
List<Flight> objects = (ArrayList<Flight>) read;
return objects;
} catch (IOException | ClassNotFoundException ex) {
ex.printStackTrace();
return new ArrayList<>();
}
}
#Test
public void testGetAll() {
try (ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream("flights.txt")))) {
Object read = ois.readObject();
expected = (ArrayList<Flight>) read;
} catch (IOException | ClassNotFoundException ex) {
ex.printStackTrace();
}
Collection<Flight> actual = flightService.getAll();
assertEquals(expected, actual);
}
Hi I have serious problem with testing. Is the above code a correct way to test? Please help me
So say your class is given the file to read in the constructor, like this:
class FlightReader {
File file;
public FlightReader(File f) {
file = f;
}
// your getAll here
}
then a test would first create a file of its own with known data, then read it, then verify the results are as expected, like this:
#Test
public void testGetAll() {
Flight f1 = new Flight("ACREG1", "B737");
Flight f2 = new Flight("ACREG2", "A320");
Flight f3 = new Flight("ACREG3", "B777");
List<Flight> written = new ArrayList<>(Arrays.asList(f1, f2, f3));
File tempFile = File.createTempFile("flights", "test");
// write sample data
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(tempFile))) {
oos.writeObject(written);
}
// data is written to a file, read it back using the tested code
FlightReader reader = new FlightReader(tempFile);
List<Flight> readFlights = reader.getAll();
// verify the written and read data are the same
assertThat(readFlights).contains(f1, f2, f3);
}
Some notes:
you should use specific classes - like in this case ArrayList - as little as possible. Why cast to an ArrayList if you just return a Collection in the end?
you shouldn't use Java Serialization at all; it's error-prone, a security risk, and considered a mistake by the Java architects.
I need to write a class that has two static methods: writeFile and readFile. However, after I do my readFile(), it returns nothing.
class writereadFile {
public static void writeFile(ArrayList<Object> list, File file){
try {
try (FileOutputStream fos = new FileOutputStream(file);ObjectOutputStream oos = new ObjectOutputStream(fos)) {
oos.writeObject(list);
oos.close();
}
}catch(IOException e){e.getMessage();}
}
public static ArrayList<Object> readFile(ArrayList<Object>list, File file){
try {
try (FileInputStream fis = new FileInputStream(file);ObjectInputStream ois = new ObjectInputStream(fis)) {
Object o = ois.readObject();
list = (ArrayList<Object>) o;
ois.close();
}
}catch(IOException | ClassNotFoundException e){e.getMessage();}
System.out.println(list);
return list;
}
}
EDIT:
This my class for testing. My object is an arraylist of custom objects if you need the custom object just comment.
class main {
public static void main(String[] args) {
Date date = new Date();
Book b1 = new Book("abc", "Phi", true, date, null);
Book b2 = new Book("cba", "Someone", true, date, null);
Books booklist = new Books();
booklist.add(b1);
booklist.add(b2);
File filetoDo = new File("book.txt");
//write arraylist into file
writereadFile.writeFile(booklist, filetoDo);
//clear the arraylist
booklist.clear();
//read book from file
writereadFile.readFile(booklist, filetoDo);
System.out.println(booklist);
}
}
Your test should read:
bookList = writereadFile.readFile(booklist, filetoDo);
and, by the way, you should really refactor your readFile method to simply:
public static ArrayList<Object> readFile(File file)
You can't modify the argument reference like that, since Java is always pass-by-value call semantics. (You could modify the list argument contents inside the function, but that's not what you are doing.)
If you are using Java 8 try using Streams:
public static readFile(String filePath) {
List<Object> list = new ArrayList<>();
try (Stream<String> stream = Files.lines(Paths.get(filePath))) {
stream.forEach(list::add);
} catch (IOException e) {
e.printStackTrace();
}
return list;
}
I'm playing around this topic a bit on my own, so below you can find some code snippets that might help you.
Examples are very short and simple, so I hope you will not just use e.printStackTrace() in your code :)
public class ExternalIO {
private ExternalIO() {
}
public static ObjectOutputStream objectOutputStream(String basePath, String pathToFile) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream(createFileIfDoesNotExist(absolutePath(basePath, pathToFile)));
return new ObjectOutputStream(fileOutputStream);
}
public static ObjectInputStream objectInputStream(String basePath, String pathToFile) throws IOException {
FileInputStream fileInputStream = new FileInputStream(absolutePath(basePath, pathToFile));
return new ObjectInputStream(fileInputStream);
}
private static File createFileIfDoesNotExist(String absolutePath) throws IOException {
File file = new File(absolutePath);
if (file.exists()) {
return file;
}
file.getParentFile().mkdirs();
file.createNewFile();
return file;
}
private static String absolutePath(String basePath, String pathToFile) {
return Paths.get(basePath, pathToFile).toAbsolutePath().toString();
}
}
output usage:
List<ItemType> input = null; //create your input list here
try (ObjectOutputStream objectOutputStream = ExternalIO.objectOutputStream(CONFIG, FILENAME)) {
objectOutputStream.writeObject(input);
} catch (Exception e) {
e.printStackTrace();
}
input usage:
try (ObjectInputStream objectInputStream = ExternalIO.objectInputStream(CONFIG, FILENAME)) {
return (List<ItemType>) objectInputStream.readObject();
} catch (Exception e) {
e.printStackTrace();
}
hope that helps ; )
Ok so i have two classes: Content and TrackUserChanges . They have the same fields.
public class Content{
private Long id;
......
private SortedSet<Content> children = new TreeSet<Content>();
}
public class TrackUserChanges{
private Long id;
.....
private SortedSet<Content> children = new TreeSet<Content>();
}
I want to clone the data from Content to TrackUserChanges:
I have the children from an instance of content:
SortedSet<Content> children = content.getChildren();
This can contain many other contents, and that contents can have also children, etc.
SortedSet<TrackUserChanges> children1 = convertContentSetToTrackUserChangesSet(children);
This is the method:
public SortedSet<TrackUserChanges> convertContentSetToTrackUserChangesSet(SortedSet<Content> children){
SortedSet<TrackUserChanges> children1 = new TreeSet<TrackUserChanges>();
for(Content c : children){
TrackUserChanges trackU = new TrackUserChanges();
trackU.setCategory(c.getCategory());
trackU.setId(c.getId());
trackU.setBook(c.getBook());
trackU.setInsertUser(c.getInsertUser());
trackU.setParent(c.getParent());
trackU.setParentId(c.getParentId());
trackU.setRelativeSortOrder(c.getRelativeSortOrder());
trackU.setText(c.getText());
trackU.setType(c.getType());
children1.add(trackU);
}
return children1;
}
I need somehow to call recusively or something like that... and I can't do trackU.setChildren(c.getChildren()) because the types don't match :/
#Mifmif
try {
FileOutputStream fout = new FileOutputStream("a.dat");
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(content);
oos.close();
}
catch (Exception e) { e.printStackTrace(); }
TrackUserChanges trackUserChanges11 = new TrackUserChanges();
try {
FileInputStream fin = new FileInputStream("a.dat");
MyCustomObjectInputStream custom = new MyCustomObjectInputStream(fin);
// custom.readClassDescriptor();
trackUserChanges11 = (TrackUserChanges) custom.readObject();
System.out.println("IDDDDD" + trackUserChanges11.getId());
custom.close();
}
catch (Exception e) { e.printStackTrace(); }
ClassCastException :)
If you have two classes with identical properties that have identical behaviour, separate those fields/behaviour into a separate class and extend that class in your other classes. This should allow you to copy directly between them.
Make your class implements Cloneable. Then just call the function clone of the SortedSet.
http://docs.oracle.com/javase/7/docs/api/java/lang/Cloneable.html
Here is a solution based on serialization , make both of your class serializable and if you want to go from one class instance to another, serialize your instance into a file , and read it using MyCustomObjectInputStream :
class MyCustomObjectInputStream extends ObjectInputStream {
public MyCustomObjectInputStream(InputStream in) throws IOException {
super(in);
}
#Override
protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
ObjectStreamClass resultClassDescriptor = super.readClassDescriptor();
if (resultClassDescriptor.getName().equals("name.of.the.package.OldClassName"))
resultClassDescriptor = ObjectStreamClass.lookup(name.of.the.package.NewClassName.class);
return resultClassDescriptor;
}
}
I resolved the problem
public TrackUserChanges convertContentToTrack(Content c) {
TrackUserChanges t = new TrackUserChanges();
t.setCategory(c.getCategory());
t.setId(c.getId());
t.setBook(c.getBook());
t.setInsertUser(c.getInsertUser());
t.setParent(c.getParent());
t.setParentId(c.getParentId());
t.setRelativeSortOrder(c.getRelativeSortOrder());
t.setText(c.getText());
t.setType(c.getType());
if (c.getChildren().size() == 0) {
return t;
}
SortedSet<TrackUserChanges> childs = new TreeSet<TrackUserChanges>();
for (Content content : c.getChildren()) {
childs.add(convertContentToTrack(content));
}
t.setChildren(childs);
return t;
}
Thanks anyway :)
This thing come to my mind when I implemented custom Marker Interface. As the Serializable Marker interface is used for Serialization in java, I made my own Marker Interface to set a flag at class level.
public class MIOne implements Serializable,MarkerInterface{
private int one;
private String str;
public MIOne() {
super();
this.one = 1;
this.str = "MIOne";
}
Object writeObject() throws IOException {
if (!(this instanceof MarkerInterface)) {
FileOutputStream out = new FileOutputStream("D:\\testTransients.ser");
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(this);
} else {
System.out.println("Unable to Support Searialization");
}
return null;
}
Object readObject() throws IOException, ClassNotFoundException {
if (!(this instanceof MarkerInterface)) {
FileInputStream fis = new FileInputStream("D:\\testTransients.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
MIOne c = (MIOne) ois.readObject();
} else {
System.out.println("Unable to Support Searialization");
}
return null;
}
}
But in this I have to make a blank Interface, than implement my logic accordingly (using instanceOf operator). I need your help to sort the same problem with some other better and simpler solution. Is that possible?
I want to store an object from my class in file, and after that to be able to load the object from this file. But somewhere I am making a mistake(s) and cannot figure out where. May I receive some help?
public class GameManagerSystem implements GameManager, Serializable {
private static final long serialVersionUID = -5966618586666474164L;
HashMap<Game, GameStatus> games;
HashMap<Ticket, ArrayList<Object>> baggage;
HashSet<Ticket> bookedTickets;
Place place;
public GameManagerSystem(Place place) {
super();
this.games = new HashMap<Game, GameStatus>();
this.baggage = new HashMap<Ticket, ArrayList<Object>>();
this.bookedTickets = new HashSet<Ticket>();
this.place = place;
}
public static GameManager createManagerSystem(Game at) {
return new GameManagerSystem(at);
}
public boolean store(File f) {
try {
FileOutputStream fos = new FileOutputStream(f);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(games);
oos.writeObject(bookedTickets);
oos.writeObject(baggage);
oos.close();
fos.close();
} catch (IOException ex) {
return false;
}
return true;
}
public boolean load(File f) {
try {
FileInputStream fis = new FileInputStream(f);
ObjectInputStream ois = new ObjectInputStream(fis);
this.games = (HashMap<Game,GameStatus>)ois.readObject();
this.bookedTickets = (HashSet<Ticket>)ois.readObject();
this.baggage = (HashMap<Ticket,ArrayList<Object>>)ois.readObject();
ois.close();
fis.close();
} catch (IOException e) {
return false;
} catch (ClassNotFoundException e) {
return false;
}
return true;
}
.
.
.
}
public class JUnitDemo {
GameManager manager;
#Before
public void setUp() {
manager = GameManagerSystem.createManagerSystem(Place.ENG);
}
#Test
public void testStore() {
Game g = new Game(new Date(), Teams.LIONS, Teams.SHARKS);
manager.registerGame(g);
File file = new File("file.ser");
assertTrue(airport.store(file));
}
}
The solution of this problem is that when you are using other objects, let say class A, into a collection like HashMap and want to serialize the HashMap object, then implement the interface Serializable for class A like this:
class A implements Serializable {
}
...
HashMap<Integer,A> hmap;
...
Otherwise that object will not be serializable.
I hope it will solve this problem now.
Try oos.flush() before you close it.
Please remenber that the whole object graph is persisted during serialize. If you have some references to GUI classes for example, you either have to make them serializable, too, or tag them as "transient", so Java won't serialize them.