Why wasn't java.io.Serializable deprecated in Java 5? - java

In pre Java 5, there were no annotations. As a result you could not add metadata to a class.
To mark a class as serializable, you had to implement the Serializable interface (which is just that, a marker) and use further transient keywords to mark a field as non serializable if needed, something like:
public class MyClass implements Serializable {
...
private transient Bla field;
...
}
Now you could theoretically make use of annotations (this is a perfect use for them) and have:
#Serializable
public class MyClass {
...
#Transient
private Bla field;
...
}
But the interface and the keyword were not deprecated and no annotation was added in Java 5 to replace them.
What are the considerations for this decision to keep the interface and the keyword?
Off course there is the issue of compatibility with pre Java 5 code, but at some point that will end (e.g. related to the new features of generics, the JLS specifies that It is possible that future versions of the Java programming language will disallow the use of raw types). So why not prepare the way for serialized annotations also?
Any thoughts? (although I would prefer concrete references :D which I was unable to find)

The interface is there so methods can be defined to accept objects of type Serializable:
public void registerObject(Serializable obj);

Off course there is the issue of compatibility with pre Java 5 code ...
Yes. This is the root of the problem.
If they #deprecated the Serializable interface in (say) Java 5, then lots of old pre-Java 5 code would give warnings (or errors depending on compiler switches).
There's nothing actually wrong with using Serializable and "forcing" people to replace it is annoying. (People have better things to do ...)
When people have "fixed" this in their code, it will no longer compile using a pre-Java 5 compiler, or run on a pre-Java 5 JVM.
It is a bad idea to do things that make the compiler systematically "cry wolf".
... but at some point that will end.
In reality, the chance of this actually happening is (IMO) small. As far as I'm aware, Sun / Oracle have never removed a deprecated feature. Not even dangerous ones like Thread.stop() and friends.
As a footnote, the Go developers are taking a different approach to this problem. When they want to change a language or library feature, they just do it. They provide a converter that will automatically rewrite your code as required.

Serializable and transient are indeed two things that could have been replaced by annotations.
They haven't been deprecated probably because there are a lot of programs that use Serializable and it would have been annoying for millions if developers if the compiler would suddenly start spewing out thousands of deprecation warnings.
There are lots of other things in the standard Java API that could have been deprecated long ago - for example, the legacy collection classes Vector and Hashtable (and I'm sure you can easily find many more things). And there are other things that could have been implemented using annotations (for example the keyword volatile, strictfp and synchronized).

Deprecation is for things that are actively harmful. What you're suggesting is forcing authors of eight years of existing Java code (at the time) to rewrite it, for no advantage, just to shut up the deprecation compiler warnings, to get back to the fully correct code they had with Java 1.4. That would not be useful.

Related

Turning abstract class without fields to interface (Java, Sonar rule s1610)

I refer to this rule:
With Java 8's "default method" feature, any abstract class without direct or inherited field should be converted into an interface.
In my perception default + private methods in Java8+ interfaces is a
pure compromise JDK designers took in order to solve a dilemma they faced: they had to introduce new methods (for ex. Map interface)
without breaking old code that used those interfaces (backward
compatibility).
In practice JDK designers introduced implementation inheritance in places
where interface inheritance existed, so potentially they
increased coupling and brittleness of our existing and future code.
In my perception introduced implementation inheritance now diminishes cool nature of interfaces - the multiple inheritance.
I understand why "abstract classes without fields" is mentioned in Sonar rule. By this the authors of the rule do lessen brittleness (but don't eliminate the fact of implementation inheritance). Compare to problems of Scala traits that do permit fields (new Java interfaces look more and more like Scala's traits) - Scala lang designers tried to solve those problems with things like trait linearization, lazy vals, etc.
I'm avoiding arguments like "it is in JDK so it is a pattern", let us speak more at the conceptual level here.
Question: Could anyone explain me why Sonar promotes this, IMHO, flawed rule?
What do we gain by such a rule? What benefit/use case am I missing here?
Thanks.
I don't necessarily agree with the rule, but I see where it's coming from.
The thing is that you don't really lose anything in this case. The only time you'd run into problems with regard to multiple inheritance would be if you implemented several interfaces containing methods with the same signature and different implementations.
However, this is forbidden by Java (you'd need to provide your own implementation of that method), so there is no danger in doing so.
In general, interfaces are more versatile than classes, so it makes sense to use them if possible.
As a counter point, the interface default feature was introduced to allow adding methods to existing interfaces without breaking existing code, but that's not the case here.

Why serialVersionUID is not enforced by Java

serialVersionUID seems to me to have a very loose specification. Any body developing a class with serializable interface can burn his hands with InvalidClassException. Also, i saw a fellow dev using int as a datatype rather than long.
So, my question why the Java designers and developers did not do something more concrete like whenever we implement serializable we have to implement a method setting serialVersionUID like the hashcode method.
So, what am i missing ? Does not seem like a double edged sword to me.
Update 1:
My bad i gave a wrong example comparing a class level thing with a instance level thing.I have seen many production issues across different companies because of this. But my general idea was cant it be made more strict by compiler in any way.
Keep in mind the requirements:
the bytes making up the ID must be present within the stream of bytes representing a serialized object
unless you invent something "on top", the only way to get there is by using a field
the ID must be identical for all objects of a class, thus the source of the ID should be static
Now step back:
there is no polymorphism for static methods
in that sense, it doesn't make a difference if you use a static field or call a static method to acquire the ID bytes when serializing an object
but you are going to write those bytes into the stream anyway
Conclusion: using a static field addresses all the above points
. When you would be using a method - you still have to create that field. Let that sink in: when using a method, the implementation must call the method, write that as field into the byte stream - and when reading the byte stream, that number needs to be consumed - as it can't be mapped to a "real" field in the class. Compare that to: there is a static field that gets written into the byte stream and read from there.
So - from a technical point of view, the natural way to integrate such in ID somehow is by asking for a static field on the class.
Of course you could have invented something else. Modern day java might have used annotations. But such usage of annotations wasn't around when Java was invented (and this kind of serialization is in Java since day 1).
And then: modern day java doesn't use "byte stream" oriented serialization in the first place.
Or as the answer from Stephen suggest - you could compute that ID based on the current content of the class. But again: this technology was invented 20 years ago. Back then, computing the id might have cost you 1, 5, 10 seconds. Compare that to the efforts of reading a static field.
So, my question why the Java designers and developers did not do something more concrete like whenever we implement serializable we have to implement a method setting serialVersionUID like the hashcode method.
If I understand you correctly, you are saying that there should be a method to calculate the serialVersion. I can see problems with this:
How would an application program calculate a decent serial version? Note that it must be calculated from type information ... not the values of fields.
Calculating a serial version at run time (repeatedly) would be expensive.
If we have lazy programmers who don't use the "serialver" tool to calculate a proper version number, the same lazy programmers are likely to implement this (hypothetical) method to return a bogus number ... and we are back where we started.
There are use-cases where NOT changing the serial version ID is intentional.
No. The real solution to the problem of lazy programmers is code reviews.
Or ... maybe ... tooling to either regenerate the serialVersion constants, or flag them as suspicious.
Note that tools can't pick all of the cases where there is going to be a problem. However, neither can a code-reviewer. And code-reviewers get tired, have to be paid, etc.
(Finally, it might be a good idea if certain IDE's didn't offer setting the constant to -1 as a quick-fix ...)
But my general idea was cant it be made more strict by compiler in any way.
It is not a compiler thing. It is a runtime behavior of a specific set of library classes. The classes use Unsafe ... but the compiler is not aware of the significance of the serialVersionID variable.
Why the Java designers and developers did not [make us] have to
implement a method setting serialVersionUID
The serialVersionUID is data related to the class. It's not data related to a single instance of the class.
If we had an interface such as:
interface MySerializable
{
long getSerialVersionUID();
}
then we could implement that like this:
class Foo implements MySerializable
{
private String myField;
//...
public long getSerialVersionUID()
{
if(myField.equals("hello"))
{
return 1L;
}
else
{
return 2L
}
}
}
This doesn't make sense. The version cannot depend on the instance.
Now that we have annotations, a good solution in my eyes would be to write a #Serializable annotation. I prefer this because anything related to serialization is really just metadata. Adding an additional field completely unrelated to the class's behaviour just muddies the water.
#Serializable(ID = "1")
class Foo
{
//...
}
Of course, annotations are a more recent addition so this wasn't an option when serialVersionUID was devised.

Not serializable class with strings only [duplicate]

We work heavily with serialization and having to specify Serializable tag on every object we use is kind of a burden. Especially when it's a 3rd-party class that we can't really change.
The question is: since Serializable is an empty interface and Java provides robust serialization once you add implements Serializable - why didn't they make everything serializable and that's it?
What am I missing?
Serialization is fraught with pitfalls. Automatic serialization support of this form makes the class internals part of the public API (which is why javadoc gives you the persisted forms of classes).
For long-term persistence, the class must be able to decode this form, which restricts the changes you can make to class design. This breaks encapsulation.
Serialization can also lead to security problems. By being able to serialize any object it has a reference to, a class can access data it would not normally be able to (by parsing the resultant byte data).
There are other issues, such as the serialized form of inner classes not being well defined.
Making all classes serializable would exacerbate these problems. Check out Effective Java Second Edition, in particular Item 74: Implement Serializable judiciously.
I think both Java and .Net people got it wrong this time around, would have been better to make everything serializable by default and only need to mark those classes that can't be safely serialized instead.
For example in Smalltalk (a language created in 70s) every object is serializable by default. I have no idea why this is not the case in Java, considering the fact that the vast majority of objects are safe to serialize and just a few of them aren't.
Marking an object as serializable (with an interface) doesn't magically make that object serializable, it was serializable all along, it's just that now you expressed something that the system could have found on his own, so I see no real good reason for serialization being the way it is now.
I think it was either a poor decision made by designers or serialization was an afterthought, or the platform was never ready to do serialization by default on all objects safely and consistently.
Not everything is genuinely serializable. Take a network socket connection, for example. You could serialize the data/state of your socket object, but the essence of an active connection would be lost.
The main role of Serializable in Java is to actually make, by default, all other objects nonserializable. Serialization is a very dangerous mechanism, especially in its default implementation. Hence, like friendship in C++, it is off by default, even if it costs a little to make things serializable.
Serialization adds constraints and potential problems since structure compatibility is not insured. It is good that it is off by default.
I have to admit that I have seen very few nontrivial classes where standard serialization does what I want it to. Especially in the case of complex data structures. So the effort you'd spend making the class serializble properly dwarves the cost of adding the interface.
For some classes, especially those that represent something more physical like a File, a Socket, a Thread, or a DB connection, it makes absolutely no sense to serialize instances. For many others, Serialization may be problematic because it destroys uniqueness constraints or simply forces you to deal with instances of different versions of a class, which you may not want to.
Arguably, it might have been better to make everything Serializable by default and make classes non-serializable through a keyword or marker interface - but then, those who should use that option probably would not think about it. The way it is, if you need to implement Serializable, you'll be told so by an Exception.
I think the though was to make sure you, as the programmer, know that your object my be serialized.
Apparently everything was serializable in some preliminary designs, but because of security and correctness concerns the final design ended up as we all know.
Source: Why must classes implement Serializable in order to be written to an ObjectOutputStream?.
Having to state explicitely that instances of a certain class are Serializable the language forces you to think about if you you should allow that. For simple value objects serialization is trivial, but in more complex cases you need to really think things through.
By just relying on the standard serialization support of the JVM you expose yourself to all kinds of nasty versioning issues.
Uniqueness, references to 'real' resources, timers and lots of other types of artifacts are NOT candidates for serialization.
Read this to understand Serializable Interface and why we should make only few classes Serializable and also we shopuld take care where to use transient keyword in case we want to remove few fields from the storing procedure.
http://www.codingeek.com/java/io/object-streams-serialization-deserialization-java-example-serializable-interface/
Well, my answer is that this is for no good reason. And from your comments I can see that you've already learned that. Other languages happily try serializing everything that doesn't jump on a tree after you've counted to 10. An Object should default to be serializable.
So, what you basically need to do is read all the properties of your 3rd-party class yourself. Or, if that's an option for you: decompile, put the damn keyword there, and recompile.
There are some things in Java that simply cannot
be serialized because they are runtime specific. Things like streams, threads, runtime,
etc. and even some GUI classes (which are connected to the underlying OS) cannot
be serialized.
While I agree with the points made in other answers here, the real problem is with deserialisation: If the class definition changes then there's a real risk the deserialisation won't work. Never modifying existing fields is a pretty major commitment for the author of a library to make! Maintaining API compatibility is enough of a chore as it is.
A class which needs to be persisted to a file or other media has to implement Serializable interface, so that JVM can allow the class object to be serialized.
Why Object class is not serialized then none of the classes need to implement the interface, after all JVM serializes the class only when I use ObjectOutputStream which means the control is still in my hands to let the JVM to serialize.
The reason why Object class is not serializable by default in the fact that the class version is the major issue. Therefore each class that is interested in serialization has to be marked as Serializable explicitly and provide a version number serialVersionUID.
If serialVersionUID is not provided then we get unexpected results while deserialzing the object, that is why JVM throws InvalidClassException if serialVersionUID doesn't match. Therefore every class has to implement Serializable interface and provide serialVersionUID to make sure the Class presented at the both ends is identical.

How unsafe is the use of sun.misc.Unsafe actually?

I am wondering about how unsafe the use sun.misc.Unsafe actually is. I want to create a proxy of an object where I intercept every method call (but the one to Object.finalize for performance considerations). For this purpose, I googled a litle bit and came up with the following code snippet:
class MyClass {
private final String value;
MyClass() {
this.value = "called";
}
public void print() {
System.out.println(value);
}
}
#org.junit.Test
public void testConstructorTrespassing() throws Exception {
#SuppressWarnings("unchecked")
Constructor<MyClass> constructor = ReflectionFactory.getReflectionFactory()
.newConstructorForSerialization(MyClass.class, Object.class.getConstructor());
constructor.setAccessible(true);
assertNull(constructor.newInstance().print());
}
My consideration is:
Even though Java is advertised as Write once, run everywhere my reality as a developer looks rather like Write once, run once in a controllable customer's run time environment
sun.misc.Unsafe is considered to become part of the public API in Java 9
Many non-Oracle VMs also offer sun.misc.Unsafe since - I guess - there are quite some libraries already use it. This also makes the class unlikely to disappear
I am never going to run the application on Android, so this does not matter for me.
How many people are actually using non-Oracle VMs anyways?
I am still wondering: Are there other reasons why I should not use sun.misc.Unsafe I did not think of? If you google this questions, people rather answer an unspecified because its not safe but I do not really feel it is besides of the (very unlikely) possibility that the method will one day disappear form the Oracle VM.
I actually need to create an object without calling a constructor to overcome Java's type system. I am not considering sun.misc.Unsafe for performance reasons.
Additional information: I am using ReflectionFactory in the example for convenience which delegates to Unsafe eventually. I know about libraries like objenesis but looking at the code I found out that they basically do something similar but check for other ways when using Java versions which would not work for me anyways so I guess writing four lines is worth saving a dependency.
There are three significant (IMO) issues:
The methods in the Unsafe class have the ability to violate runtime type safety, and do other things that can lead to your JVM "hard crashing".
Virtually anything that you do using Unsafe could in theory be dependent on internal details of the JVM; i.e. details of how the JVM does things and represents things. These may be platform dependent, and may change from one version of Java to the next.
The methods you are using ... or even the class name itself ... may not be the same across different releases, platforms and vendors.
IMO, these amount to strong reasons not to do it ... but that is a matter of opinion.
Now if Unsafe becomes standardised / part of the standard Java API (e.g. in Java 9), then some of the above issues would be moot. But I think the risk of hard crashes if you make a mistake will always remain.
During one JavaOne 2013 session Mark Reinhold (the JDK architect) got a question: "how safe it is to use the Unsafe class?". He replied with sort of surprising answer: "I believe its should become a stable API. Of course properly guarded with security checks, etc..."
So it looks like there may be something like java.util.Unsafe for JDK9. Meanwhile using the existing class is relatively safe (as safe as doing something unsafe can be).

Keeping track of what's in a Collection in pre-generics Java?

For a bunch of reasons that (believe it or not) are not as unsound as you may think, we are still (sigh) using Java 1.4 to build and run our code (though we plan to finally move to Java 7 by the end of the year).
Our existing code that uses Collection classes doesn't do a very good job of making it clear what is expected to be in the Collection. Obviously, you can read the code and see what the downcasts end up being done and infer from that, but you can't just look at a method declaration and know what the Collection object that is a method argument or method return value actually holds.
In new code that I'm writing and when I am in older code that uses Collections, I've been adding in-line comments to Collections declarations to show what would have been declared if generics were being used. For example:
Map/*<String, Set<Integer>>*/ theMap = new HashMap/*<String, Set<Integer>>*/();
or
List/*<Actions>*/ someMethod(List/*<Job>*/ jobs);
In keeping with the frowning at subjectivity here at SO, rather than asking what you think of this (though admittedly I'd like to know -- I do find it a bit ugly but still like having the type info there) I'd instead just ask what, if anything, you do to make it clear what is being held by pre-generics Collection objects.
What we recommended back in the old days -- and I was a Java Architect at Sun when Java 1.1 was the New Thing -- was to write a class around the structure (I don't think 1.1 even had Collection as a base class) so that the typecasts happned in code you control instead of in user code. So, for example, something like
public class ArrayOfFoo {
Object [] ary; // ctor left as exercise
public void set(int index, Foo value){
ary[index] = (Object) value; // cast strictly not needed, any Foo is an Object
}
public void get(int index){
return (Foo) ary[index]; // cast needed, not every Object is a Foo
}
}
Sounds like the code base you have isn't built to this convention; if you're writing new code, there's no reason you can't start. Failing that, your convention isn't bad, but it's easy to forget the cast and then have to search to find out why you're getting a bad cast exception. It's mildly better to resort of some variant on Hungarian notation, or the Smalltalk 'aVariable' convention, by encoding the type in the names, so that you use
Object fooAry = new Object[aZillion];
fooAry[42] = new Foo();
Foo aFoo = fooAry[42];
Use clear variable identifiers such as jobList, actionList, or dictionaryMap. If you're concerned with the type of objects they contain, you could even make it a convention to always let the identifier of a Collection hint about which type of objects it holds.
The inlined comments aren't that idea actually. When I ported a 1.5 project back to 1.4 I did just that (instead of removing the type parameters). It worked out quite well.
I'd recommend writing tests. For various reasons:
You should be writing tests anyway!
You can assert the type of a collection member very easily to ensure that all your code paths are adding the right types to the collection
You can use the test to write code that serves as an "example" of how to use the collection correctly
If you just need binary compatibility to 1.4 you could consider using a tool to downgrade the class files back to 1.4 and thus start to develop in 1.6 or 1.7 right now. You would of course need to avoid any API that hasn't been there in 1.4 (unfortunately you can't compile code with generics against the 1.4 jars directly as they don't declare any generic types). The Bytecode is still the same (at least with 1.6, I don't know for sure about 1.7). One free tool that can do the trick is ProGuard. It can do much more sophisticated things and can also remove all traces of generics in the class files. Just turn off the obfuscation and optimization if you don't need it. It will also warn you if some missing API was used in the processed code if you feed it the 1.4 libraries.
I'm aware that is considered a hack by many but we had a similar requirement where we needed some code to still run on a Personal Java VM (this is essentially Java 1.1) and several other exotic VMs and this approach worked quite well. We started with ProGuard and then made our own tool for the task to be able to implement a few workarounds for some Bugs in the diverse VMs.

Categories