Here is a very simple generic class:
import java.io.Serializable;
public class GenericDemoObject<T> implements Serializable {
private static final long serialVersionUID = 1L;
T date;
#Override
public String toString() {
return date.getClass().getName() + ':' + date.toString();
}
}
I then created an instance of GenericDemoObject with T typed to org.joda.time.LocalDate, and serialized it to disk. Then I tried to deserialize it with the following code:
private static Object deserialize(String fileName) throws IOException, ClassNotFoundException {
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName))) {
return in.readObject();
}
}
// LocalDate is java.time.LocalDate
GenericDemoObject<LocalDate> obj = (GenericDemoObject<LocalDate>) deserialize("GenericDemoObject.ser");
I can't understand how the deserialization works. Why does it not throw a ClassCastException?
Edited:
More precisely, I mean obj is a reference of type GenericDemoObject, however the deserilized object's date field is of type org.joda.time.LocalDate. How can that assignment work?
After testing the case you posted in your question I confirm that you won't get an exception by merely casting a generic as you did, the real casting never happens until you access the field date, check the following code:
public class Main {
public static void main(String[] args) {
org.joda.time.LocalDate date = org.joda.time.LocalDate.now();
GenericDemoObject<org.joda.time.LocalDate> gdo = new GenericDemoObject<>();
gdo.date = date;
try {
serialize("GenericDemoObject.ser", gdo);
} catch (IOException | ClassNotFoundException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
try {
GenericDemoObject<java.time.LocalDate> obj1 = (GenericDemoObject<java.time.LocalDate>) deserialize("GenericDemoObject.ser");//no exception
GenericDemoObject<String> obj2 = (GenericDemoObject<String>) deserialize("GenericDemoObject.ser");//no exception
LocalDate date1 = obj1.date;//The exception is thrown here
String date2 = obj2.date;//The exception is thrown here
} catch (ClassNotFoundException | IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
private static Object deserialize(String fileName) throws IOException, ClassNotFoundException {
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName))) {
return in.readObject();
}
}
private static void serialize(String fileName, Object object) throws IOException, ClassNotFoundException {
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileName))) {
out.writeObject(object);
}
}
}
class GenericDemoObject<T> implements Serializable {
private static final long serialVersionUID = 1L;
T date;
#Override
public String toString() {
return date.getClass().getName() + ':' + date.toString();
}
}
I hope this answers your question.
Note:
Reading through comments again I think Antoniossss really answered but didn't really post it as an answer.
Related
I have a custom Java exception class, CustomRestException:
import org.codehaus.jettison.json.JSONObject;
public class CustomRestException extends Exception{
private String httpStatusMessage;
private Integer httpStatusCode;
private String endpointBody;
private String callType;
private List<HashMap<String,String>> headerParams;
private List<HashMap<String,String>> queryParams;
private JSONObject endPointErrorResponse;
public CustomRestException (RestCallParameters p,String type,String url,String body,UniformInterfaceException ue) {
super(p.getCollectionErrMsg());
this.endpointBody= body;
this.endPointUrl = url;
this.callType = type;
setUniformInterfaceExceptionParameters(ue);
}
private void setUniformInterfaceExceptionParameters(UniformInterfaceException ue) {
try {
this.httpStatusMessage = ue.getMessage();
this.httpStatusMessage = ue.getResponse().getClientResponseStatus().toString();
this.httpStatusCode = ue.getResponse().getStatus();
this.endPointErrorResponse =
new JSONObject(ue.getResponse().getEntity(String.class));
}
catch (Exception ex) {
LOGGER.info("[setUniformInterfaceExceptionParameters] Ecnountered error ",ex);
}
}
}
I am throwing this CustomRestException from a method:
public String myMethod() throws CustomRestException {
try{
//make some rest call here
}catch(UniformInterfaceException ue){
throw new CustomRestException (p,"POST",url,p.getReqBody(),ue);
}
}
then, I am catching this CustomRestException somewhere else:
public Response myEndPointMethod(){
try{
//some code
myClassObj.myMethod(); //calling myMethod() above
//some code
} catch (CustomRestException e) {
LOGGER.error("(someMessage) CustomRestException ", e);
}
My problem
this.endPointErrorResponse = new JSONObject(ue.getResponse().getEntity(String.class));
If this line throws any exception (I have seen only JSONException so far), the program terminates after executing this logger in the catch block:
LOGGER.info("[setUniformInterfaceExceptionParameters] Ecnountered error ",ex);
My Expectation
The logger LOGGER.error("(someMessage) CustomRestException ", e); in myEndPointMethod() should be called.
Are we not supposed to handle (try-catch) exceptions inside custom exceptions?
Any idea where I am going wrong?
I have been struggling to create a serializing method that serializes all my already existing objects. This is what I have done:
my class:
public class Test implements Serializable{
ArrayList<TheOtherClass> obj = new ArrayList<>();
public static void main(String[] args) {
Test test = new Test();
test.addTest("This", "Is", "Some");
test.addTest("Text", "As", "Example");
test.saveAllArrays();
}
// omitted code down here.
public void addTest(String some, String random, String text) {
obj.add(new TheOtherClass(some, random, text));
}
public void saveTest(Object obj) throws IOException{
ObjectOutputStream save = new ObjectOutputStream(new FileOutputStream("SaveFile.bin"));
save.writeObject(obj);
}
public void saveAllArrays(){
for(TheOtherClass all : obj){
try {
saveTest(all);
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}
my object class:
public class TheOtherClass implements Serializable{
private String some;
private String random;
private String savedText;
Getter and setter methods are omitted.
Here is a complete example. Hopefully it will get you moving.
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class Test implements Serializable {
private static final String FILE = "SaveFile.bin";
private List<Item> itemList = new ArrayList<>();
public class Item implements Serializable {
private String first;
private String second;
private String last;
public Item(String first, String second, String last) {
this.first = first;
this.second = second;
this.last = last;
}
#Override
public String toString() {
return first + ", " + second + ", " + last;
}
}
public static void main(String args[]) {
Test test = new Test();
if(args.length > 0) {
try {
test.loadItemList();
System.out.println("loaded");
test.printList();
} catch (IOException | ClassNotFoundException e) {
System.out.println(e.getMessage());
}
} else {
test.addItem("1", "2", "done");
test.addItem("Text", "As", "Example");
try {
test.saveItemList();
System.out.println("saved");
test.printList();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
private void printList() {
itemList.forEach(System.out::println);
}
private void addItem(String first, String second, String last) {
itemList.add(new Item(first, second, last));
}
private void loadItemList() throws IOException, ClassNotFoundException {
InputStream inputStream = new FileInputStream(FILE);
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
itemList = (List<Item>) objectInputStream.readObject();
}
private void saveItemList() throws IOException {
OutputStream outputStream = new FileOutputStream(FILE);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(itemList);
}
}
At present you're creating a new file per serialized object, so you lose all but the last one. There is no need to serialize multiple objects at all, or iterate over the array list. Just save it directly, and deserialize it directly too.
So I'm working with JSON in Java and JSON can have a base of either an Array or an Object. In my Config class, I take a class as an argument so I can create the file accordingly if it doesn't exist. I also store the class as a private field so I know in future.
However, when I get to reading the file, I'd prefer to have multiple return types though the same method name. If I return Object, I then have to cast the returned value which I want to avoid.
Current code:
public class Config {
private File dir = null;
private File file = null;
private Class clazz = null;
public Config(String program, String fileName, Class root) throws IOException {
this.dir = new File(System.getProperty("user.home") + File.separator + program);
if (!this.dir.exists()) {
this.dir.mkdir();
}
this.file = new File(this.dir + File.separator + fileName);
if (!this.file.exists()) {
this.file.createNewFile();
if (root.getName().equals(JSONArray.class.getName())) {
Files.write(this.file.toPath(), "[]".getBytes());
} else if (root.getName().equals(JSONObject.class.getName())) {
Files.write(this.file.toPath(), "{}".getBytes());
}
}
this.clazz = root;
}
public JSONArray readConfig() {
return null;
}
public JSONObject readConfig() {
return null;
}
}
Is there anyway I can do what I want without having to return Object?
multiple return types though the same method name
well, it is possible to use generic function to achieve that. For example,
public static void main(String[] args) {
try {
String t = getObject(String.class);
Integer d = getObject(Integer.class);
} catch (Exception e) {
e.printStackTrace();
}
}
public static <T> T getObject(Class<T> returnType) throws Exception {
if(returnType == String.class) {
return (T) "test";
} else if(returnType == Integer.class) {
return (T) new Integer(0);
} else {
return (T) returnType.newInstance();
}
}
Will the following code even compile?
I'm afraid no. There are few compilation errors such as
public Object readConfig() {
try {
// Assume jsonString exists
return (this.clazz.getDeclaredConstructor(String.class).newInstance(jsonString)); <--- clazz should be getClass()
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
e.printStackTrace();
<---- missing return statement
}
}
I have two classes , utilisateur ( means user in french ) and Envellope ( wich means envelope ), so i have many classes to organize sending and receiving objects to/from two classes in localhost !
I want to print the result in the screen after sending and receiving.
I conclude that it's not deserializing and the output of toString is a kind of hashcode like this #14ae5a5
Envellope class:
public class Envellope<T> implements Serializable{
private static final long serialVersionUID = -5653473013975445298L;
public String todo;
public T thing;
public Envellope() {
}
public Envellope(String todo, T thing) {
this.todo = todo;
this.thing = thing;
}
}
Utilisateur class:
public class utilisateur implements Serializable{
private static final long serialVersionUID = -5429001491604482315L;
public String login;
public String mdp;
public utilisateur(String l,String m){
login=l;
mdp=m;
}
public utilisateur(){}
}
and there is the main (Client):
public static void main(String[] args) {
try {
Socket socket=new Socket("localhost",4444);
StreamObject so=new StreamObject(socket);
Envellope<utilisateur> toSend=new Envellope<utilisateur>("Authenticate",new utilisateur("addou","ismail"));
so.send(toSend);//sending to ServerSocket
Envellope<utilisateur> env=(Envellope<utilisateur>) so.receive();//receiving from server
System.out.println(env.todo+" Object: "+env.thing);
} catch (IOException ex) {
Logger.getLogger(Aaa.class.getName()).log(Level.SEVERE, null, ex);
}
}
I didn't write here the other classes, because i think it works , but if you need it just tell me !
StreamObject class:
public class StreamObject extends IOS{
private ObjectOutputStream oos;
private ObjectInputStream ois;
public StreamObject(Socket s) throws IOException{
super();
super.os=s.getOutputStream();
super.is=s.getInputStream();
oos=new ObjectOutputStream(os);
ois=new ObjectInputStream(is);
}
And IOS class is just inputStream and OutputStream !
public void send(Object object) {
try {
oos.writeObject(object);
} catch (IOException e) {
System.out.print("Erreur receive socket: ");
System.err.print("IOException ");
System.out.println(e.getMessage());
}
}
public Object receive() {
try {
return ois.readObject();
} catch (ClassNotFoundException e) {
System.out.print("Erreur receive socket: ");
System.err.print("ClassNotFoundException ");
System.out.println(e.getMessage());
} catch (IOException e) {
System.out.print("Erreur receive socket: ");
System.err.print("IOException ");
System.out.println(e.getMessage());
}
return null;
}
}
Your utilisateur class does not override toString, so it uses the default implementation, which returns the class name and hash code.
Add something like this to utilisateur:
#Override
public String toString() {
return "login="+login+" & mdp="+mdp;
}
I´ve been reading that the static fields are not serialized but, after testing it, I saw that´s not true.
The static modifier even overrides the transient modifier and makes the field serializable.
I write one example from a book that shows that a static transient field is serialized.
import java.io.*;
class USPresident implements Serializable {
private static final long serialVersionUID = 1L;
#Override
public String toString() {
return "US President [name=" + name
+ ", period=" + period + ", term=" + term + "]";
}
public USPresident(String name, String period, String term) {
this.name = name;
this.period = period;
this.term = term;
}
private String name;
private String period;
private static transient String term;
}
class TransientSerialization {
public static void main(String[] args) {
USPresident usPresident = new USPresident("Barack Obama", "2009 to --", "56th term");
System.out.println(usPresident);
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("USPresident.data"))) {
oos.writeObject(usPresident);
} catch (IOException ioe) {
// ignore
}
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("USPresident.data"))) {
Object obj = ois.readObject();
if (obj != null && obj instanceof USPresident) {
USPresident presidentOfUS = (USPresident) obj;
System.out.println(presidentOfUS);
}
} catch (IOException ioe) {
// ignore
} catch (ClassNotFoundException e) {
// ignore
}
}
}
Is wrong the general concept that static fields are not serialized? Is it just a recommendation?
Why the transient modifier doen't take effect with static ?
note: I understand that initialize a static field in a constructor is an odd code, but the compiler let me do it and it's just in order to understand static fields serialization.
This has nothing to do with serialization but due to the fact that you are setting the static field when you create your usPresident variable. This sets the field for the class of that JVM. Try reading in the serialized president in a different program and see that the transient field is not serialized.
As an aside: consider not ignoring your exceptions.
For example, refactored, your code could look like this:
class USPresident implements Serializable {
private static final long serialVersionUID = 1L;
#Override
public String toString() {
return "US President [name=" + name + ", period=" + period + ", term="
+ term + "]";
}
public USPresident(String name, String period, String term) {
this.name = name;
this.period = period;
this.term = term;
}
private String name;
private String period;
private static transient String term;
}
class TransientSerialization {
public static void main(String[] args) {
serializePresident();
deserializePresident();
}
private static void deserializePresident() {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(
"USPresident.data"));
Object obj = ois.readObject();
if (obj != null && obj instanceof USPresident) {
USPresident presidentOfUS = (USPresident) obj;
System.out.println(presidentOfUS);
}
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static void serializePresident() {
USPresident usPresident = new USPresident("Barack Obama", "2009 to --",
"56th term");
System.out.println(usPresident);
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("USPresident.data"));
oos.writeObject(usPresident);
oos.close();
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
if (oos != null) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
The second time your run it, change the main method to:
public static void main(String[] args) {
// serializePresident();
deserializePresident();
}
And see what comes up.
For me, the first run returns:
US President [name=Barack Obama, period=2009 to --, term=56th term]
US President [name=Barack Obama, period=2009 to --, term=56th term]
and the second run returns:
US President [name=Barack Obama, period=2009 to --, term=null]