I have a problem with serialization of a class using the singleton pattern. First let me introduce the code:
import java.io.ObjectStreamException;
import java.io.Serializable;
import org.ejml.simple.SimpleMatrix;
public class Operation implements Serializable {
private static final long serialVersionUID = 1L;
private final static int CONSTANT = 10;
private SimpleMatrix data;
private Long timestamp;
private static Operation instance = new Operation ();
private Operation () {
data = new SimpleMatrix(1, CONSTANT);
}
protected static Operation getInstance() {
return instance;
}
//Hook for not breaking the singleton pattern while deserializing.
private Object readResolve() throws ObjectStreamException {
return instance;
}
protected void setData(SimpleMatrix matrix) {
this.data = matrix;
}
protected SimpleMatrix getData() {
return data;
}
public Long getTimestamp() {
return timestamp;
}
public void setTimestamp(Long timestamp) {
this.timestamp = timestamp;
}
}
I have three problems with it hoping that somebody can help me:
As far as I know, static fields are no serialized. So if I deserialize is my final static field CONSTANT set to 10? If not, how can I make this? This is very important.
As you can see, in the constructor a new matrix is created. If I deserialize, is my data overwritten by this constructor? For deserialization I want the data of the serialized version and not a new matrix. The constructor I only need the first time before serialization to instantiate the object.
Before I serialize I will set the field timestamp to the time of serialization. After deserialization I would like to compare this field with the timestamp of some files (to see if files have changed since serialization). What sort of timestamp should I use for both the serialization time and the last modified time of files so that I can easily compare?
The static constant is associated with the class, so serialization and deserialization of your instance won't impact it at all.
For the deserialization to work, you need to set the singleton's data to the deserialized instance data:
private Object readResolve() throws ObjectStreamException {
instance.setData(getData());
return instance;
}
The timestamp can stay as a Long, that's fine. Use System.currentTimeMillis(), you'll be able to compare with a File object lastModified() date. Just set the field when you serialize:
private void writeObject(java.io.ObjectOutputStream out)
throws IOException{
timestamp=System.currentTimeMillis();
out.defaultWriteObject();
}
A test I've made to be sure of what I say, using a String instead of a matrix as in your code:
public static void main(String[] args) throws Exception {
Operation op=getInstance();
op.setData("test1");
byte[] ds=serialize();
System.out.println(new Date(getInstance().timestamp));
op.setData("test2");
deserialize(ds);
System.out.println(getInstance().getData());
}
This gives me the current date and test1, since the deserialize instance has overriden the current instance. serialize and deserialize simply convert between the instance and bytes.
I would suggest that you adopt the Enum Singleton approach for implementing Singletons, as handling Serialization would be done for free. In your case it would be
public enum Operation {
INSTANCE;
// No need to handle Serialization
}
Quoting Joshua Bloch in Effective Java "a single-element enum type is the best way to implement a singleton."
There are plenty benefits to this approach, you can find out here
And also For instance control, prefer enum types to readResolve
Related
I have a serializable class.
public class Customer implements Externalizable {
private static final long serialVersionUID = 1L;
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName( String name) {
this.name = name;
}
#Override
public String toString() {
return "id : "+id+" name : "+name ;
}
#Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
this.setId((String) in.readObject());
this.setName((String) in.readObject());
}
#Override
public void writeExternal(ObjectOutput out) throws IOException {
System.out.println("Reached here");
out.writeObject(id);
out.writeObject(name);
}
}
I have serialized the object of the class into a file. Now I have changed the datatype of name from String to List. So while deserializing, I am getting a class cast exception because it is not able to convert from String to List.
I was thinking of changing the version of the class every time some change is made to the class so that in the readExternal I can handle it explicitly. However while this idea might be able to work for simple classes it would fail in case of larger complicated classes. Can anyone please provide a simpler solution to this.
Thanks
You just have to manage the different possibilities (and perform the appropiate conversion) yourself.
#Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
this.setId((String) in.readObject());
Object nameField = in.readObject();
if (nameField != null) {
boolean resolved = false;
if (nameField instanceof String) {
ArrayList<String> list = new ArrayList<String>(); // Or whatever you want to for converting the String to list.
list.add((String)nameField);
this.setName(list);
resolved = true;
}
if (nameField instanceof List) {
this.setName((List<String>) nameField);
resolved = true;
}
if (!resolved) {
throw new Exception("Could not deserialize " + nameField + " into name attribute");
}
}
}
I suggest you take a look at different different serialization engine such as Protocol Buffers, Apache Avro or Apache Thrift.
Other possiblities : use a Strategy pattern to select serialization algorithm and delegate to it on readExternal/writeExternal. However you still need a "selector". Class identifier (full name ?) and version are generally top candidates but serialization layout (ie String+String ou String+List) is also an alternative.
You best implement a migration tool for converting serialized objects from one version to another (by deserializing it to an instance of the old class and then creating an instance of the new class and copying the fields). Keep it simple, no need for overly clever code.
I also recommend to not implement a migration algorithm in your readExternal method for a better separation of concerns, not to mention most likely improved performance, because you could and should omit readExternal for the deserialization provider is usually doing a pretty good job and unless you don't deserialize the same old object over and over again the branch (is it version x or y?) would only yield once to the "old" branch but evaluated for every deserialization. And last but not least: Code you don't have is code you don't need to maintain -> improved maintainability.
Btw: The idea of the serialVersionUID field is to give the deserialization implementation a hint that a serialized object cannot be deserialized to an instance of the same class, because it has changed (thus making it a different class with the same name). If you don't change the version field when making changes, it's completely useless and you can set it to 0 or anything constant and never touch it.
I want to know how deserilize a class who contain staic attributes from file because when I create an instance from project , I can't affect it to the global class
My Code : ( deserialize method doesn't work )
public class Project implements Serializable{
private static String name;
private static String site;
private static Table table;
public static String getName() {
return Project.name;
}
public static void setName(String name) {
Project.name = name;
}
public static String getSite() {
return Project.site;
}
public static void setSite(String site) {
Project.site = site;
}
public static Table getTable() {
return Project.table;
}
public static void setTable(Table table) {
Project.table = table;
}
// Serialize
public static boolean serialize(String path){
try{
FileOutputStream fout = new FileOutputStream(path);
Crypto.encrypt(Project.class, fout);
return true;
}catch(Exception ex){
return false;
}
}
public static boolean deserialze(String path){
try{
FileInputStream fin = new FileInputStream(path);
Project project = (Project) Crypto.decrypt(fin);// decrypt file
Project.name = project.getName();
Project.site = project.getSite();
Project.table = project.getTable();
return true;
}catch(Exception ex){
return false;
}
Serialization works with objects — instances of classes. But static fields aren't part of an instance. So serialization doesn't touch them.
You're not actually serializing an instance of your Project class, though. You're serializing the class object itself, which is an instance of the java.lang.Class class. I can see why you'd think that might store your static fields, but it doesn't: a class object is for reflection, getting information about the class. It doesn't actually hold the class's data; the static fields in the class are not fields of the Project.class object. AFAIK, serializing a class object is generally not a useful thing to do.
Your fields look like they probably shouldn't be static anyway, because they hold information that should be different for each project. Right now, you have a single name that's shared across all projects, and a single site, and a single table. You could run new Project() fifty times and have fifty distinct objects, but there's no way to make them different from each other. Your program has no way to represent two projects with different names.
My advice: take out all the static keywords, change your static field references (e.g. Project.name) to instance field references (e.g. this.name), create an instance of your class (e.g. Project project = new Project()) and set its fields, and serialize that.
If you're going to implement java.io.Serializable interface remember that when you deserializing transient or static fields they most likely gonna have default value (null for Object types).
Static field also get default value if there are no objects in the scope (otherwise it get initialized with the value that is defined for an existing object).
Is it required to make the fields of an Immutable class private as if they are marked as final , can not be changed ?
I mean isn't it enough to just mark the fields as final ?
(I know that it's not necessary for an immutable class to have final fields but it's advisable to have it for compile time check for the class internally.)
No this is not enough.
Consider this example:
final class ImmutableClass {
private final List<String> data;
public ImmutableClass(final List<String> data) {
this.data = data;
}
public List<String> getData() {
return data;
}
}
This class is final so cannot be extended. It's data field is final so cannot be changed after it is assigned.
But:
final ImmutableClass immutableClass = new ImmutableClass(data);
immutableClass.getData().add("Some other value");
Oops.
So to make a class truly immutable all fields should also be immutable classes, or have defensive copies.
For example, to correct the issues about you would need to do this:
final class ImmutableClass {
private final List<String> data;
public ImmutableClass(final List<String> data) {
this.data = new ArrayList<>(data);
}
public List<String> getData() {
return Collections.unmodifiableList(data);
}
}
And this only works because String is immutable. If you had, for instance, a List<Date> you would also need to copy the individual Date objects.
Having private variables accessed through getters gives you more freedom with the implementation of the class. You can, for example, replace a trivial getter with an implementation which calculates or retrieves the value on access or caches the result.
Another reason to keep fields as private even when they are final is when the field is a mutable object. In that case the object can be changed even though it is final which is usually not what you want. Here is an example of a presumably immutable class with a public final field of the mutable Date class.
class DateHolder {
public final Date date;
DateHolder(Date date) {
this.date = date:
}
}
// ...
DateHolder holder = new DateHolder(Date.now());
// this doesn't work because date is final:
//holder.date = new Date(2013, 11, 23);
// but this works even though date is final:
holder.date.setYear(2013);
final fields can only be assigned to from within the constructor. Therefore, making fields final is enough to make them immutable after construction. Assigning pointers to mutable objects to them is a different story.
Is there any way to make field static or transient using java reflection API.
EDIT: I have some Beans that are already being serialised using soap api and is being used by some clients, for some clients i don't want to expose one or two fields.
Sure there are so many ways to do it without changing or adding transient keyword.
Just want to know if it can be done, and if so, how ?
EDIT: I wouldn't call it an API or framework issue, more like a design flaw...
I'm using apache axis2 for soap
No. Such a thing would require modifying the byte code of the class. A particular difficulty in the case of static fields is that they are accessed using different bytecodes than object fields.
I don't see a why a field couldn't be made transient in runtime, at least in theory, but the current reflection API doesn't allow it. See also: Can a field's transient property/flag be set through reflection in java?
You can't do it with the reflection api. I think there are some byte-code manipulation tools but in this case you can use the Decorator pattern. It solves the problem but I think it is extremely ugly:
(I omited the usual boilerplate from here such as interfaces)
public class StaticDecorator {
private static Object staticField;
private Object yourObject;
public StaticDecorator(Object yourObject) {
this.yourObject = yourObject;
}
public static Object getStaticField() {
return staticField;
}
public static void setStaticField(Object object) {
staticField = object;
}
}
I used Object for the type of the class you are going to wrap but of course you can substitute any type you want. Using an approach like this you can "decorate" any class with a static field.
If you are really, extremely must want a static field in an object at run time this can help you but I think that there is a design flaw lurking somewhere.
You can wrap your bean inside another bean that only exposes the fields that you'd like to expose through your API. For example, with an internal bean with the fields foo, bar, and baz, where you do not want to expose baz.
Lombok Delegation can make this incredibly simple, but here's an example using plain-old-Java.
public class ExposedBean {
private InternalBean internalBean;
public ExposedBean(InternalBean internalBean) {
this.internalBean = internalBean;
}
public String getFoo() { return internalBean.getFoo(); }
public String getBar() { return internalBean.getBar(); }
}
public class InternalBean {
private String foo;
private String bar;
private String baz;
public String getFoo() { return foo; }
public String getBar() { return bar; }
public String getBaz() { return baz; }
}
Original answer, regarding setting modifiers
You can not set modifiers. You can check them, however.
Field myField = /* get a field object */;
if (Modifier.isTransient(myField.getModifiers()) {
System.out.println("myField is transient.");
}
if (Modifier.isFinal(MyClass.class.getModifiers()) {
System.out.println("MyClass is final.");
}
With more information about the problem you're trying to solve, we can suggest alternatives. Member#getModifiers() is not declared final, so you could possibly use a decorator. (The below code is 100% untested.)
public class FieldModifierDecorator extends Field {
protected Field field;
private int modifiers = -1;
public static void decorate(Field field) {
FieldModifierDecorator newInstance = new FieldModifierDecorator();
newInstance.field = field;
return newInstance;
}
public void overrideModifiers(int modifiers) {
this.modifiers = modifiers;
}
public int getModifiers() {
if (-1 == modifiers) {
return field.getModifiers();
}
return modifiers;
}
}
// Example usage
public Field makeFieldAppearTransient(Field field) {
FieldModifierDecorator decoratedField = FieldModifierDecorator.decorate(field);
decoratedField.overrideModifiers(field.getModifiers() | Modifier.TRANSIENT);
// if (Modifier.isTransient(decoratedField.getModifiers())) {
// System.out.println("It looks transient, but really isn't.");
//}
return decoratedField;
}
Modfifying class information or byte code modification is definitely the wrong tool for the job. You are trying to solve a business problem with solely technical tools.
It sounds more like you need a permission concept. Users may have permission to see some fields. Based on that you could use java bean introspection to clear the values of those fields just before they are sent to the client.
However this might have its problems as well. A client should be able to determine if it has permission to see that field or not.
There is a specific class in a third party library that I want to serialize. How would I go about doing this?
I'm assuming I will have to write a method that takes in an object of the class and uses reflection to get the private member values. Then for deserialization I would use reflection to put the values back.
Would this work? Is there an easier way?
You could just use a transfer object that implements Serializable, and has the same fields as the third party object. Let the transfer object implement a method that returns an object of the original third party class and you're done:
Pseudocode:
class ThirdParty{
int field1;
int field2;
}
class Transfer implements Serializable{
int field1;
int field2;
/* Constructor takes the third party object as
an argument for copying the field values.
For private fields without getters
use reflection to get the values */
Transfer (ThirdParty orig){
this.field1=orig.field1;
this.field2=orig.field2;
}
ThirdParty getAsThirdParty(){
ThirdParty copy=new ThirdParty();
copy.field1=this.field1;
copy.field2=this.field2;
return copy;
}
/* override these methods for custom serialization */
void writeObject(OutputStream sink);
void readObject(InputStream src);
}
You just have to make sure that the members are serialized correctly if you got any special member objects.
Alternatively if the third party class isn't final you could just extend it, have that implement Serializable and write your own writeObject and readObject methods.
Check here for some serialization infos:
Serialization Secrets - WayBack
Serialization API - Oracle
Serialization Secrets - Old
You need to wrap it into something that does the serialization.
Ideally, the third-party class supports some other form of serialization, for example XML serialization (which is based on bean properties). If not, you have to roll your own. Whether that involves reflection or just getters, setters and constructors depends on the class.
In any case, the wrapper would convert the object into a byte[] or a String or something else and write that into the serialization output. On deserialization it reconstructs the object from that data.
The two methods your wrapper has to implement are
private void writeObject(java.io.ObjectOutputStream out)
throws IOException
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException;
A lot depends on the nature of the third party class. Is it final, does it have a no argument constructor, can you construct it given known values or is it constructed by another class, does it itself contain non-Serializable members?
Easiest way is to decompile the class, add an implements Serializable, and recompile it, but if it contains non-Serializable members, things get more complicated.
Another possible solution may be to define a set of private methods inside your Serializable class that uses the instances of the third party class.These special methods are part of a special callback contract the serialization system offers.These methods will be called during the serialization/deserialization process.
Their signatures must be like:
private void writeObject(ObjectOutputStream os) {
// your code for saving the third party variables
}
private void readObject(ObjectInputStream is) {
// your code to read the third party state, create a new ThirdParty instance,
// and assign it to your class.
}
This example clarifies this idea further:
public class MyClass implements Serializable
{
transient private ThirdParty thirdPartyInstance ;
private int myClassVariable ;
private void writeObject(ObjectOutputStream oos)
{
try
{
oos.defaultWriteObject();
oos.writeInt(thirdPartyInstance.getThirdPartyVariable());
oos.writeInt(thirdPartyInstance.getFourthPartyInstance().getFourthPartyVariable());
}
catch(Exception e)
{
e.printStackTrace();
}
}
private void readObject(ObjectInputStream ois)
{
try
{
ois.defaultReadObject(); //the call to defaultReadObject method must always be before any other code in the try block
//Reconstructing thirdPartyInstance
thirdPartyInstance =new ThirdParty(ois.readInt(),new FourthParty(ois.readInt()));
}
catch(Exception e)
{
e.printStackTrace();
}
}
MyClass(int myClassVariable, ThirdParty thirdPartyInstance)
{
this.myClassVariable=myClassVariable;
this.thirdPartyInstance=thirdPartyInstance;
}
ThirdParty getThirdPartyInstance()
{
return thirdPartyInstance;
}
int getMyClassVariable()
{
return myClassVariable;
}
public static void main(String args[])
{
FourthParty fourthPartyInstance=new FourthParty(45);
ThirdParty thirdPartyInstance=new ThirdParty(13,fourthPartyInstance);
MyClass myClassInstance=new MyClass(7,thirdPartyInstance);
System.out.println("Before: ThirdParty variable value is "+myClassInstance.getThirdPartyInstance().getThirdPartyVariable());
System.out.println("Before: FourthParty variable value is "+myClassInstance.getThirdPartyInstance().getFourthPartyInstance().getFourthPartyVariable());
System.out.println("Before: MyClass variable value is "+myClassInstance.getMyClassVariable());
try
{
FileOutputStream fios=new FileOutputStream("D://TestFileq.ser");
ObjectOutputStream oos=new ObjectOutputStream(fios);
oos.writeObject(myClassInstance);
oos.close();
FileInputStream fi = new FileInputStream("D://TestFileq.ser");
ObjectInputStream objectIn = new ObjectInputStream(fi);
MyClass myClassInst = (MyClass)objectIn.readObject();
System.out.println("After: ThirdParty variable value is "+myClassInst.getThirdPartyInstance().getThirdPartyVariable());
System.out.println("After: FourthParty variable value is "+myClassInst.getThirdPartyInstance().getFourthPartyInstance().getFourthPartyVariable());
System.out.println("After:MyClass variable value is "+myClassInst.getMyClassVariable());
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
class ThirdParty
{
private int thirdPartyVariable;
private FourthParty fourthPartyInstance;
ThirdParty(int thirdPartyVariable,FourthParty fourthPartyInstance)
{
this.thirdPartyVariable=thirdPartyVariable;
this.fourthPartyInstance=fourthPartyInstance;
}
int getThirdPartyVariable()
{
return thirdPartyVariable;
}
FourthParty getFourthPartyInstance()
{
return fourthPartyInstance;
}
}
class FourthParty
{
private int fourthPartyVariable;
FourthParty(int fourthPartyVariable)
{
this.fourthPartyVariable=fourthPartyVariable;
}
int getFourthPartyVariable()
{
return fourthPartyVariable;
}
}
Note that the thirdPartyInstance in MyClass must be declared transient otherwise an exception of type 'java.io.NotSerializableException' occurs.
For more explanation see:
SCJP Sun Certified Programmer for Java 6 by 'Cathy Sierra',Page Number 497