I have a class as follows in a .jar file (library file):
class A{
//someimplementation
}
I would like to make it to implements Serializable interface as follows:
class A implements Serializable {
//the same implementation as present in classA
}
I do not want to decompile the jar file, changing the class signature and then archiving it again after compilation.
Is there any way like writing hooks to achieve this? Kindly provide any pointers/suggestions.
My ultimate aim is to achieve implementing Serializable interface without modifying the jar file.
You can probably achieve this using Serialization Proxy Pattern (Effective Java 2nd edition Item 78)
A few links about the Pattern :
http://jtechies.blogspot.com/2012/07/item-78-consider-serialization-proxies.html
http://java.dzone.com/articles/serialization-proxy-pattern
Follow up: instance control in Java without enum
Make a new class that extends A and is Serializable. In order to avoid serialization errors, however, because A isn't serializable, you need to make a SerializationProxy that creates a new instance via constructor or factory method instead of the normal Java Serialization mechanism of explicitly setting the fields outside of any constructor.
public class MySerializableA extends A implements Serializable{
private final Foo foo;
private final Bar bar;
...
private Object writeReplace() {
return new SerializationProxy(this);
}
//this forces us to use the SerializationProxy
private void readObject(ObjectInputStream stream) throws InvalidObjectException {
throw new InvalidObjectException("Use Serialization Proxy instead.");
}
//this private inner class is what actually does our Serialization
private static class SerializationProxy implements Serializable {
private final Foo foo;
private final Bar bar;
...
public SerializationProxy(MySerializableA myA) {
this.foo = myA.getFoo();
this.bar = myA.getBar();
...//etc
}
private Object readResolve() {
return new MySerializableA(foo, bar,...);
}
}
}
The only downside is when you want to serialize an A, you will have to wrap it in a MyA. but when deserializing, the cast to A will work fine.
Related
I am running an embedded hazelcast deployment and storing a ConcurrentMap<String, MyType>, where the type of value in the map is my custom class.
MyType
public class MyType implements Serializable {
private MyTag tag;
...
}
One of its fields is an interface MyTag.
MyTag
public interface MyTag<T> {
}
And I have a class containing several enum implementations of MyTag interface:
MyTags
public class MyTags {
public static enum Integers implements MyTag<Integer> {
INT_TAG1,
INT_TAG2,
...
}
public static enum Strings implements MyTag<String> {
STRING_TAG1,
...
}
...
}
After moving MyTags class to a different package and redeploying one of my services (with MyType in the new package) upon attempting a get on the map, an exception is thrown:
com.hazelcast.nio.serialization.HazelcastSerializationException: java.lang.ClassNotFoundException: old.package.MyTags$Strings
How could I protect myself from this situation when deploying on a production environment?
Java's Serializable depends on the class remaining the exact same. A moved class is no longer the same class. Select one of the other options that Hazelcast has for serialization of objects. See Comparing Serialization Options for some more guidance on the different options.
I have the following serializable class (implements serializable):
public class Test implements Serializable{
private String id;
private Map<String,Object> otherProperties;
}
However , it seems like this property is causing some problems with serialization :
How can I solve this problem ?
Also , is there any downside in not making this transient or serializable ? Will I be able to serialize this class fully ?
The Map interface does not extend the Serializable interface, which is why Sonar is warning you.
When serializing an instance of Test, you must choose whether or not you want otherProperties to be serialized.
If you don't want to serialize otherProperties, then the field should be marked as transient:
private transient Map<String, Object> otherProperties;
Otherwise, you can change the type of otherProperties to an implementation of Map that implements Serializable, such as HashMap.
If it's an option (for instance, if you are using Jackson to (de)serialize your class), remove the Serializable marker from your Test class. The serialization will still work and you will get rid of the warning in Sonar.
Add this 2 methods to your class:
private void writeObject(java.io.ObjectOutputStream stream)
throws IOException {
stream.defaultWriteObject();
}
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
}
Map value type should be specified to extends Serialzable:
public class Test<T extends Serializable> implements Serializable{
private String id;
private Map<String,T> otherProperties;
}
I was having a similar issue but in contrast to Nexussim Lements I've been using an interface that gets serialized but still SonarLint showed me a warning:
public class BasicCheck implements Serializable { ... }
public class Case implements Serializable {
private BasicCheck basicCheck; // Sonarlint throws warning here
...
}
Luckily I've found FAlfeao's solution to be working. All I had to do was to add these two methods to my Case-class:
private void writeObject(java.io.ObjectOutputStream stream)
throws IOException {
stream.defaultWriteObject();
}
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
}
I have multiple services (in Spring MVC) that are children of a global Service. So I need to know about the best practice (or your opinions) with multiple methods with this example:
//Domain classes
public class MyParentObject{}
public class MyObj extends MyParentObject{}
//Services
public class MyParentObjectServiceImpl implements MyParentObjectService{
#Override
public MyParentObject findObjectByProp(String prop, String objectType){
//myCode (not abstract class)
}
}
public class MyObjServiceImpl extends MyParentObjectServiceImpl implements MyObjectService{
private myObjType = "MyObj";
#Override
public MyObj findMyObjByProp(String prop){
return (MyObj) super.findObjectByProp(prop, this.myObjType);
}
}
And in this approach, I use calls like this:
MyObj foo = myObjService.findMyObjByProp(prop);
So I need to know if this approach is "better" or more apropiate that calling directly the parent method with the second parameter. E.g:
MyObj foo = (MyObj)myParentObjectService.findObjectByProp(prop, "MyObj");
..and avoiding the creation of second methods, more specific. It is important to know that the children services will be created anyway, because we have lot of code that is specific of a domain objects.
I have the idea that the first approach is better, because is more readable, but I need to support that decision with some documents, blog, or opinions to discuss this designs with my colleagues.
This looks like a tagged class hierarchy. It's difficult to comment on the value of this design in general without knowing the details. However, a slightly different approach that I would recommend is to generify your base class to gain a little bit of type safety.
In particular:
public /* abstract */ class MyParentObjectServiceImpl<T extends MyParentObject>
implements MyParentObjectService{
MyParentObjectServiceImpl(Class<T> type) { this.type = type; }
private final Class<T> type; // subclasses provide this
#Override
public T findObjectByProp(String prop){
//you can use type for object specific stuff
}
}
public class MyObjServiceImpl extends MyParentObjectServiceImpl<MyObj>
// You might not need this interface anymore
// if the only method defined is findMyObjByProp
/* implements MyObjectService */ {
MyObjServiceImpl() {
super(MyObj.class);
}
#Override
public /* final */ MyObj findMyObjByProp(String prop) {
return (MyObj) super.findObjectByProp(prop, this.myObjType);
}
}
You definitely gain in type safety (casting will only appear in the base class), you get rid of the "tags" (the strings that identify the different objects) and possibly reduce the number of classes/interfaces required to implement the whole hierarchy. I successfully used this approach several times. Note that this works best if the base class is abstract. Food for thoughts.
I want to serialize a POJO class which is not under my control, but want to avoid serializing any of the properties which are coming from the superclass, and not from the final class. Example:
public class MyGeneratedRecord extends org.jooq.impl.UpdatableRecordImpl<...>,
example.generated.tables.interfaces.IMyGenerated {
public void setField1(...);
public Integer getField1();
public void setField2(...);
public Integer getField2();
...
}
You can guess from the example that that this class is generated by JOOQ, and inherits from a complex base class UpdatableRecordImpl which also has some bean property-like methods, which cause problems during the serialization. Also, I have several similar classes, so it would be good to avoid duplicating the same solution for all of my generated POJOs.
I have found the following possible solutions so far:
ignore the specific fields coming from superclass using mixin technique like this: How can I tell jackson to ignore a property for which I don't have control over the source code?
The problem with this is that if the base class changes (e.g., a new getAnything() method appears in it), it can break my implementation.
implement a custom serializer and handle the issue there. This seems a bit overkill to me.
as incidentally I have an interface which describes exactly the properties I want to serialize, maybe I can mixin a #JsonSerialize(as=IMyGenerated.class) annotation...? Can I use this for my purpose?
But, from pure design point of view, the best would be to be able to tell jackson that I want to serialize only the final class' properties, and ignore all the inherited ones. Is there a way to do that?
Thanks in advance.
You can register a custom Jackson annotation intropector which would ignore all the properties that come from the certain super type. Here is an example:
public class JacksonIgnoreInherited {
public static class Base {
public final String field1;
public Base(final String field1) {
this.field1 = field1;
}
}
public static class Bean extends Base {
public final String field2;
public Bean(final String field1, final String field2) {
super(field1);
this.field2 = field2;
}
}
private static class IgnoreInheritedIntrospector extends JacksonAnnotationIntrospector {
#Override
public boolean hasIgnoreMarker(final AnnotatedMember m) {
return m.getDeclaringClass() == Base.class || super.hasIgnoreMarker(m);
}
}
public static void main(String[] args) throws JsonProcessingException {
final ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector(new IgnoreInheritedIntrospector());
final Bean bean = new Bean("a", "b");
System.out.println(mapper
.writerWithDefaultPrettyPrinter()
.writeValueAsString(bean));
}
}
Output:
{
"field2" : "b"
}
You can override the superclass' methods which you'd like to prevent from being output and annotate them with #JsonIgnore. The override shifts the control of property creation to the subclass while enabling its ability to filter it from the output.
For instance:
public class SomeClass {
public void setField1(...);
public Integer getField1();
public void setField2(...);
public Integer getField2();
#Override
#JsonIgnore
public String superClassField1(...){
return super.superClassField1();
};
#Override
#JsonIgnore
public String superClassField2(...){
return super.superClassField2();
};
...
}
You can use this as well instead of unnecessary overrides
#JsonIgnoreProperties({ "aFieldFromSuperClass"})
public class Child extends Base {
private String id;
private String name;
private String category;
}
The good use of inheritance is that the child classes extend or add functionality. So the usual way is to serialize the data.
A workarround would be to use a Value Object (VO) or Data Transfer Object (DTO) with the fields you need to serialize. Steps:
Create a VO class with the fields that should be serialized.
Use BeanUtils.copyProperties(target VO, source data) to copy the properties
Serialize the VO instance.
Add the following annotation in your Base Class :
#JsonInclude(Include.NON_NULL)
I have a class that is something like the following:
public class Foo {
static byte[] convertToArray(Foo f);
static Foo convertToFoo(byte[] ba);
}
How can I use convertToArray and convertToFoo to allow Foo to implement java.io.Serializable? The default serialization procedure doesn't seem like a good solution for my class because it would require changing a lot of other classes to implement Serializable. However, I already have a way to go to and from bytes, so there should be an easy way for Foo to implement serializable without having to declare all dependent members as Serializable. I suspect overriding readObject and writeObject is the way to go, but what is the correct way to do this, since these are instance methods with return type void?
Check out Externalizable, which is a subinterface of Serializable. Its readExternal and writeExternal methods delegate the serialization details to the programmer, which sounds appropriate in your case.
During deserialization (in your implementation of readExternal), you will need to use Foo.convertToFoo to convert the bytes from an ObjectInput to a Foo object, and then copy all of the state of that Foo object into this.
A snippet from the Javadoc that describes the semantics of Externalizable:
Only the identity of the class of an
Externalizable instance is written in
the serialization stream and it is the
responsibility of the class to save
and restore the contents of its
instances. The writeExternal and
readExternal methods of the
Externalizable interface are
implemented by a class to give the
class complete control over the format
and contents of the stream for an
object and its supertypes. These
methods must explicitly coordinate
with the supertype to save its state.
These methods supersede customized
implementations of writeObject and
readObject methods.
Assuming your class is final then you probably want to use a serial proxy (see Effective Java). Implement Serializable, but make readObject, readObjectNoData and writeObject throw an exception. Use writeReplace to produce a serialisable proxy object containing the binary data. In the proxy, use readResolve to create a Foo from the data.
public final class Foo implements Serializable {
private static final long serialVersionUID = 42L;
private static final ObjectStreamField[] serialPersistentFields = { }
static byte[] convertToArray(Foo f) { ... }
static Foo convertToFoo(byte[] ba) { ... }
private void writeObject(
ObjectOutputStream out {
) throws IOException {
throw new NotSerializableException();
}
private void readObject(
ObjectInputStream in
) throws IOException, ClassNotFoundException {
throw new NotSerializableException();
}
private void readObjectNoData(
) throws ObjectStreamException {
throw new NotSerializableException();
}
private Object writeReplace() throws ObjectStreamException {
return new FooSerialProxy(this);
}
}
/* pp */ final class FooSerialProxy implements Serializable {
private static final long serialVersionUID = 42L;
private final byte[] data;
/* pp */ FooSerialProxy(Foo foo) {
this.data = Foo.convertToArray(foo);
}
private Object readResolve() throws ObjectStreamException {
return Foo.convertToFoo(data);
}
}