Actually, I searched the solution for that in web. I also found Copy an object in Java. In my object, there are a lot mapping.
Even I use Cloneable and Copy Constructor, I still need to copy for each fields?
My requirement is to know which data changed between Old Object and New Object.
My object Example Tree :
MotorProposal
- startDate : Date ---> can change
- endDate : Date ---> can change
- customer : Cutomer
- vehicleList : List<Vehicle> ---> can chnage
- carNo : String ---> can change
- loading : int ---> can change
- cubicCapacity : int ---> can chnage
- driver : Driver ---> can change
- fullName : String ---> can change
- address : Stirng ---> can change
- license : Stirng ---> can change
- expYear : int ---> can change
- model : Model
-there other fields
-there other fields
Is there another way to create new Instance with the same value without copying for each field?
My expected program
MotorProposal oldProposal = --> come from DB
MotorProposal newProposal = org.someapi.ObjectUtil.newInstance(oldProposal);
Update
Currently, I solve this case Martin Dinov suggested. As below.
ObjCopy.java
public class ObjCopy {
public static Serializable newInstance(Serializable obj) {
Serializable result = null;
try {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(buffer);
oos.writeObject(obj);
oos.flush();
oos.close();
ByteArrayInputStream in = new ByteArrayInputStream(buffer.toByteArray());
ObjectInputStream ois = new ObjectInputStream(in);
return (Serializable)ois.readObject();
} catch (Exception e) {
//do nothing
e.printStackTrace();
}
return result;
}
}
Test.java
public class Test {
public static void main(String[] args) {
Country country = new Country();
country.setName("Myanmar");
Province province_1 = new Province();
province_1.setCountry(country);
province_1.setName("Yangon");
Province province_2 = (Province)ObjCopy.newInstance(province_1);
province_2.getCountry().setName("USA");
System.out.println(province_1.getName() + "-" + province_1.getCountry().getName());
System.out.println(province_2.getName() + "-" + province_2.getCountry().getName());
}
}
Output
Yangon-Myanmar
Yangon-USA
How about Yoni Roit's second proposal from the Stackoverflow link you provide? In other words, serialize and then deserialize the object - so this will result in deep copying your object byte-wise. You need to have your class implement Serializable. As long as all class fields can be serialized, this approach should work. However, serializing and deserializing objects can be quite slow apparently - probably not an issue if you want to do this out of convenience, rather than out of efficiency. Here's a simple example of re-creating a new ArrayList:
ArrayList<Integer> foo = new ArrayList<Integer>();
foo.add(5);
foo.add(3);
foo.add(1);
ArrayList<Integer> obj = null;
// Write the object out to a byte array
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(foo);
out.flush();
out.close();
// Make an input stream from the byte array and read
// a copy of the object back in.
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(
bos.toByteArray()));
obj = (ArrayList<Integer>)in.readObject();
In your case, you'd want to type-cast to your specific class of course. This way you don't have to explicitly copy each field in the class.
No CyCDemo, there are a lot of issues about the Cloneable interface and the reason of and the reasons why Java has not implemented a deep copy.
In any case get an eye there:
https://code.google.com/p/cloning/
Related
This question already has an answer here:
Writing LinkedList into text file via ObjectOutputStream but output is garbage
(1 answer)
Closed 1 year ago.
I am using Spring framework, and use streamresolution to return a .txt file for user to download.
The result of data is fine, however, there is a 't' in front of every column of data,
and besides the last column, there is a 'w' in the end of every column.
I can't not understand why because the data seems fine, and I didn't told the program to create the letter.
Here is my code:
// A list of String, which are the data, it might looks like 20200810,a,b,c,100,55,.....
// the whole is a String contains comma
List<String> dataList = (List<String>) parameters.get("myData");
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
StreamingResolution streamingResolution = null;
ObjectOutputStream oos = new ObjectOutputStream(outputStream);
oos.writeObject("\n");
for (String s : dataList) {
oos.writeObject(s.trim());
oos.writeUTF("\n");
}
streamingResolution = new StreamingResolution("text/plain", new ByteArrayInputStream(outputStream.toByteArray()));
streamingResolution.setCharacterEncoding(CharEncoding.UTF_8);
String year = Integer.toString((Integer.parseInt(end.substring(0, 4));
String day = year + end.substring(4, 6);
oos.close();
return streamingResolution.setFilename(day + ".txt");
while I download the data, 202108.txt
it might looks like
t ?0210810,a,b,c,100,55w
t ?0210810,d,e,f,99,60
could anyone please tell me why there would be a 't' in the front
and a 'w' in the end?
And how to fix this?
Thanks a lot.
This code uses an ObjectOutputStream, which is used to write serialized Java data in a binary format. It is not a plain text format, and should not be used in this way. The extra characters are bytes that are defined in the Java Object Serialization Specification.
To write plain text, you can use the java.io.PrintStream class instead. For example:
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(outputStream, false, StandardCharsets.UTF_8);
printStream.println();
for (String s : dataList) {
printStream.println(s.trim());
}
printStream.flush();
StreamingResolution streamingResolution = new StreamingResolution("text/plain", new ByteArrayInputStream(outputStream.toByteArray()));
streamingResolution.setCharacterEncoding(CharEncoding.UTF_8);
Note that I also simplified the code by moving the streamingResolution local variable declaration to where it is assigned.
This is a straightforward translation of the code provided, to show you how to use the PrintStream class, however it may not be the best way to write it. The StreamingResolution class appears to be part of the Stripes Framework. It is intended for streaming large responses to the client. However, this implementation does not actually stream the response, it accumulates it into a byte array. A better way to implement this would be to subclass the StreamingResponse class, as described in the Stripe documentation, to write directly to the response:
return new StreamingResolution("text/plain") {
public void stream(HttpServletResponse response) throws Exception {
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.println();
for (String s : dataList) {
out.println(s.trim());
}
out.flush();
}
}.setFilename(day + ".txt");
I'm trying do something like that:
Person; PersonList (ArrayList) contains Person;
Summary contains PersonList;
SummaryList (ArrayList) contains Summary.
Next I want to modify my Person and save it to file, like in code below:
//first run
personList.addPerson(); // PersonArrayList: [Person: Anonymous Person]
summaryList.addSummary(personList); // SummaryArrayList: [Summary: Test, PersonArrayList: [Person: Anonymous Person]]
modifyPerson(personList); // set lastName to ModifiedPerson
// PersonArrayList: [Person: Anonymous ModifiedPerson]
// SummaryArrayList: [Summary: Test, PersonArrayList: [Person: Anonymous ModifiedPerson]]
save.savePersonListToDatabase(personList);
save.saveSummaryToDatabase(summaryList);
/*
here is OK. Is one instance of PersonList and one instance of Person. Change in Person affect to both Lists.
end of first run
*/
Next I want to read it from file. I use this code to read from file (and similar to save):
public Object readObjectFromFile(String filePath) throws IOException, ClassNotFoundException {
fileInputStream = new FileInputStream(filePath);
objectInputStream = new ObjectInputStream(fileInputStream);
Object object = objectInputStream.readObject();
System.out.println("Read " + filePath + " is OK");
objectInputStream.close();
return object;
}
public PersonList readPersonListFromDatabase() {
try{
String personFilePath = "PersonList.obj";
personList = (PersonList) readObjectFromFile(personFilePath);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return personList;
}
and second run:
//second run
personList = read.readPersonListFromDatabase();
summaryList = read.readSummaryListFromDatabase();
/*
here is NOT ok. There are two instances of PersonList and two instances of Person. Change in Person does
not affect on SummaryList (because there are different instances of it)
*/
I use Serializable and FileOutputStream / ObjectOutputStream to save it.
I want to run program, do my things, save it all and close. In next run I want to read it all from files.
What should I do, if I want to keep all references after read from file?
Finally, I found the solution.
Follow to this post https://stackoverflow.com/a/10374665/14558334
I create a "container" class which looks like that:
public class ClassContainer implements Serializable {
private SummaryList summaryList;
private PersonList personList;
public ClassContainer(SummaryList summaryList, PersonList personList) {
this.summaryList = summaryList;
this.personList = personList;
}
}
Thanks to this I save / read only one object with every references saved.
Maybe it's not the best solution, but it works fine.
I was creating a simple android application in which I am converting an object to String. How can I re-convert the object from the string?
I am converting my object to String using the following line of code.
String convertedString = object.toString();
You can't**, because that is not what the toString method is for. It's used to make a readable representation of your Object, but it's not meant for saving and later reloading.
What you are looking for instead is Serialization. See this tutorial here to get started:
http://www.tutorialspoint.com/java/java_serialization.htm
** Technically you could, but you shouldn't.
You can do it in two ways:
Java Serialization
Using Gson library (more simple), remember the the purpose of this lib is to convert simply json to object and viceversa when working with REST services.
Hope it helps
You can use Serialization to convert object to string and vise versa:
String serializedObject = "";
// serialize the object
try {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream so = new ObjectOutputStream(bo);
so.writeObject(myObject);
so.flush();
serializedObject = bo.toString();
} catch (Exception e) {
System.out.println(e);
}
// deserialize the object
try {
byte b[] = serializedObject.getBytes();
ByteArrayInputStream bi = new ByteArrayInputStream(b);
ObjectInputStream si = new ObjectInputStream(bi);
MyObject obj = (MyObject) si.readObject();
} catch (Exception e) {
System.out.println(e);
}
Use Java Serialization for doing same.
Go with below link for better understand how to convert java object.
Ex. http://www.geeksforgeeks.org/serialization-in-java/
Also You can go with this link:
How to convert the following json string to java object?
I have three class as boat,car,truck etc who extend from vehicle , I write all the object of this in a file say vehicleOrder.dat like this :
fout = new FileOutputStream("VehicleOrders.dat");
oos = new ObjectOutputStream(fout);
oos.writeObject(v); //where v is object of boat,truck car etc
Till here its good ,it writes, but when I try to read the dat file like this,
fin = new FileInputStream("VehicleOrders.dat");
ois = new ObjectInputStream(fin);
vehicle readInstance=null;
do{
readInstance = (vehicle)ois.readObject();
if(readInstance != null)
{
orderList.add(readInstance);
}
}
while (readInstance != null);
it reads the two objects which are in the dat file but after that goes to the do again and gives null pointer exception
It seems like your class doesn't have 0-param-Constructor.
Maybe this link will help you out about the explanation
ObjectInputStream expects a visible no-arg constructor for the class instance you are trying to deserialize. I assume your class doesn't have one. Add one.
I am able to serialize an object into a file and then restore it again as is shown in the next code snippet. I would like to serialize the object into a string and store into a database instead. Can anyone help me?
LinkedList<Diff_match_patch.Patch> patches = // whatever...
FileOutputStream fileStream = new FileOutputStream("foo.ser");
ObjectOutputStream os = new ObjectOutputStream(fileStream);
os.writeObject(patches1);
os.close();
FileInputStream fileInputStream = new FileInputStream("foo.ser");
ObjectInputStream oInputStream = new ObjectInputStream(fileInputStream);
Object one = oInputStream.readObject();
LinkedList<Diff_match_patch.Patch> patches3 = (LinkedList<Diff_match_patch.Patch>) one;
os.close();
Sergio:
You should use BLOB. It is pretty straighforward with JDBC.
The problem with the second code you posted is the encoding. You should additionally encode the bytes to make sure none of them fails.
If you still want to write it down into a String you can encode the bytes using java.util.Base64.
Still you should use CLOB as data type because you don't know how long the serialized data is going to be.
Here is a sample of how to use it.
import java.util.*;
import java.io.*;
/**
* Usage sample serializing SomeClass instance
*/
public class ToStringSample {
public static void main( String [] args ) throws IOException,
ClassNotFoundException {
String string = toString( new SomeClass() );
System.out.println(" Encoded serialized version " );
System.out.println( string );
SomeClass some = ( SomeClass ) fromString( string );
System.out.println( "\n\nReconstituted object");
System.out.println( some );
}
/** Read the object from Base64 string. */
private static Object fromString( String s ) throws IOException ,
ClassNotFoundException {
byte [] data = Base64.getDecoder().decode( s );
ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream( data ) );
Object o = ois.readObject();
ois.close();
return o;
}
/** Write the object to a Base64 string. */
private static String toString( Serializable o ) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream( baos );
oos.writeObject( o );
oos.close();
return Base64.getEncoder().encodeToString(baos.toByteArray());
}
}
/** Test subject. A very simple class. */
class SomeClass implements Serializable {
private final static long serialVersionUID = 1; // See Nick's comment below
int i = Integer.MAX_VALUE;
String s = "ABCDEFGHIJKLMNOP";
Double d = new Double( -1.0 );
public String toString(){
return "SomeClass instance says: Don't worry, "
+ "I'm healthy. Look, my data is i = " + i
+ ", s = " + s + ", d = " + d;
}
}
Output:
C:\samples>javac *.java
C:\samples>java ToStringSample
Encoded serialized version
rO0ABXNyAAlTb21lQ2xhc3MAAAAAAAAAAQIAA0kAAWlMAAFkdAASTGphdmEvbGFuZy9Eb3VibGU7T
AABc3QAEkxqYXZhL2xhbmcvU3RyaW5nO3hwf////3NyABBqYXZhLmxhbmcuRG91YmxlgLPCSilr+w
QCAAFEAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cL/wAAAAAAAAdAAQQUJ
DREVGR0hJSktMTU5PUA==
Reconstituted object
SomeClass instance says: Don't worry, I'm healthy. Look, my data is i = 2147483647, s = ABCDEFGHIJKLMNOP, d = -1.0
NOTE: for Java 7 and earlier you can see the original answer here
How about writing the data to a ByteArrayOutputStream instead of a FileOutputStream?
Otherwise, you could serialize the object using XMLEncoder, persist the XML, then deserialize via XMLDecoder.
Thanks for great and quick replies. I will gives some up votes inmediately to acknowledge your help. I have coded the best solution in my opinion based on your answers.
LinkedList<Patch> patches1 = diff.patch_make(text2, text1);
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(bos);
os.writeObject(patches1);
String serialized_patches1 = bos.toString();
os.close();
ByteArrayInputStream bis = new ByteArrayInputStream(serialized_patches1.getBytes());
ObjectInputStream oInputStream = new ObjectInputStream(bis);
LinkedList<Patch> restored_patches1 = (LinkedList<Patch>) oInputStream.readObject();
// patches1 equals restored_patches1
oInputStream.close();
} catch(Exception ex) {
ex.printStackTrace();
}
Note i did not considered using JSON because is less efficient.
Note: I will considered your advice about not storing serialized object as strings in the database but byte[] instead.
Java8 approach, converting Object from/to String, inspired by answer from OscarRyz. For de-/encoding, java.util.Base64 is required and used.
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Base64;
import java.util.Optional;
final class ObjectHelper {
private ObjectHelper() {}
static Optional<String> convertToString(final Serializable object) {
try (final ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(object);
return Optional.of(Base64.getEncoder().encodeToString(baos.toByteArray()));
} catch (final IOException e) {
e.printStackTrace();
return Optional.empty();
}
}
static <T extends Serializable> Optional<T> convertFrom(final String objectAsString) {
final byte[] data = Base64.getDecoder().decode(objectAsString);
try (final ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data))) {
return Optional.of((T) ois.readObject());
} catch (final IOException | ClassNotFoundException e) {
e.printStackTrace();
return Optional.empty();
}
}
}
XStream provides a simple utility for serializing/deserializing to/from XML, and it's very quick. Storing XML CLOBs rather than binary BLOBS is going to be less fragile, not to mention more readable.
How about persisting the object as a blob
If you're storing an object as binary data in the database, then you really should use a BLOB datatype. The database is able to store it more efficiently, and you don't have to worry about encodings and the like. JDBC provides methods for creating and retrieving blobs in terms of streams. Use Java 6 if you can, it made some additions to the JDBC API that make dealing with blobs a whole lot easier.
If you absolutely need to store the data as a String, I would recommend XStream for XML-based storage (much easier than XMLEncoder), but alternative object representations might be just as useful (e.g. JSON). Your approach depends on why you actually need to store the object in this way.
Take a look at the java.sql.PreparedStatement class, specifically the function
http://java.sun.com/javase/6/docs/api/java/sql/PreparedStatement.html#setBinaryStream(int,%20java.io.InputStream)
Then take a look at the java.sql.ResultSet class, specifically the function
http://java.sun.com/javase/6/docs/api/java/sql/ResultSet.html#getBinaryStream(int)
Keep in mind that if you are serializing an object into a database, and then you change the object in your code in a new version, the deserialization process can easily fail because your object's signature changed. I once made this mistake with storing a custom Preferences serialized and then making a change to the Preferences definition. Suddenly I couldn't read any of the previously serialized information.
You might be better off writing clunky per property columns in a table and composing and decomposing the object in this manner instead, to avoid this issue with object versions and deserialization. Or writing the properties into a hashmap of some sort, like a java.util.Properties object, and then serializing the properties object which is extremely unlikely to change.
The serialised stream is just a sequence of bytes (octets). So the question is how to convert a sequence of bytes to a String, and back again. Further it needs to use a limited set of character codes if it is going to be stored in a database.
The obvious solution to the problem is to change the field to a binary LOB. If you want to stick with a characer LOB, then you'll need to encode in some scheme such as base64, hex or uu.
You can use the build in classes sun.misc.Base64Decoder and sun.misc.Base64Encoder to convert the binary data of the serialize to a string. You das not need additional classes because it are build in.
Simple Solution,worked for me
public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(out);
os.writeObject(obj);
return out.toByteArray();
}
Today the most obvious approach is to save the object(s) to JSON.
JSON is readable
JSON is more readable and easier to work with than XML.
A lot of Non-SQL databases that allow storing JSON directly.
Your client already communicates with the server using JSON. (If it doesn't, it is very likely a mistake.)
Example using Gson.
Gson gson = new Gson();
Person[] persons = getArrayOfPersons();
String json = gson.toJson(persons);
System.out.println(json);
//output: [{"name":"Tom","age":11},{"name":"Jack","age":12}]
Person[] personsFromJson = gson.fromJson(json, Person[].class);
//...
class Person {
public String name;
public int age;
}
Gson allows converting List directly. Examples can be easily
googled. I prefer to convert lists to arrays first.
you can use UUEncoding