Tagged: java core

Dr. Deprecator Prescriptions: important things that you should know about obsolete Java API (JEP 277)

Did you ever asked yourself why Cloneable or, for example, Serializable interfaces are not deprecated?
OpenJDK team has a special man Stuart Marks who call himself as Dr. Deprecator. He is «Software Deconstructionist» and few days ago he made a great talk about API evolution and upcoming removing of some obsolete code in Java 9.
Doctor Deprecator
Thanks to Yoshio Terada for a photo.

The most important idea from presentation is that «Deprecated» code may be separated into four categories:
“Condemned” – will be removed or disabled in a future release (no moral connota, on). For example, from Java 9 already removed java.util.logging.LogManager.addPropertyChangeListener()
“Dangerous” – using this may introduce bugs or data loss. For example, String.getBytes() may loss for anything other than ASCII
“Superseded” – not dangerous, not going away, but new code should use something different. For example Vector, Date classes.
“Unimplemented” – some things unconditionally throw an exception at runtime (e.g. UnsupportedOperatioonException). This enables warnings at compile time. For example: class ImmutableList implements List, so should implement mutator methods add() and remove()

See this presentation

UPD
Yesterday was created JEP 277: Enhanced Deprecation

Discussion on Redit

What Might a New @Deprecated Look Like?

Annotation Library

RFC: #[deprecated] for Rust that was inspired by this JEP

JEP 277 “Enhanced Deprecation” is Nice. But Here’s a Much Better Alternative

Deprecation service in code

For example, Tapestry uses a special DeprecationWarning service which tracking usage of deprecated API. See usage example.
You may create something similar yourself.

In Python

https://wiki.python.org/moin/PythonDecoratorLibrary#Generating_Deprecation_Warnings
https://wiki.python.org/moin/PythonDecoratorLibrary#Smart_deprecation_warnings_.28with_valid_filenames.2C_line_numbers.2C_etc..29
Example
https://bitbucket.org/ecollins/passlib/src/070364a99ca7d4a0588a40485957d9a579a2d191/passlib/utils/init.py?at=default&fileviewer=file-view-default

Example of usage
https://bitbucket.org/ecollins/passlib/src/070364a99ca7d4a0588a40485957d9a579a2d191/passlib/apache.py?at=default&fileviewer=file-view-default

    @deprecated_method(deprecated="1.6", removed="1.8",
                       replacement="check_password")
    def verify(self, user, realm, password):
        """verify password for user"""
        return self.check_password(user, realm, password)
Реклама

toString() contract

Today I read great article of Fabian Kessler Java toString(): the Program Logic vs. Debug Dilemma.

In short, it is not obvious how to override method and what exactly means «string representation of object»:

Hrm. So there are mainly 2 uses:
String representation: toString() returns the object’s value «as string» as close as possible.
It is absolutely required to override toString(), and to do it in this way.

Debug information: the object’s values for the human.
For example IntelliJ IDEA’s default toString() template generates this kind.
It’s just nice to have.

JavaDoc says:

Returns a string representation of the object. In general, the
toString method returns a string that
«textually represents» this object. The result should
be a concise but informative representation that is easy for a
person to read.
It is recommended that all subclasses override this method.

Quotation from the «Effective Java» book:

One important decision you’ll have to make when implementing a toString
method is whether to specify the format of the return value in the documentation.
It is recommended that you do this for value classes, such as phone numbers or
matrices. The advantage of specifying the format is that it serves as a standard,
unambiguous, human-readable representation of the object. This representation
can be used for input and output and in persistent human-readable data objects,
such as XML documents. If you specify the format, it’s usually a good idea to pro-
vide a matching static factory or constructor so programmers can easily translate
back and forth between the object and its string representation. This approach is
taken by many value classes in the Java platform libraries, including BigInteger ,
BigDecimal , and most of the boxed primitive classes.

I found that most of code that I saw uses some unwritten «toString() contact». The contract mostly based on difference between Entity and Value objects.

1. «String typization» mechanism

The Delphi programming language has a great conception of Variant type. It is difficult to me to explain this in few words. It is like an universal container for the primitive types.

This is like a def keyword in Groovy: it mean any type. But any primitive type, not an basic Object.
And there is convention like a «Groovy Truth» how one primitive type should be converted to another.

Unfortunately Java hasn’t Variant type, so it uses String as it replacement. Hence, any primitive type you can convert to sting presentation: numbers, dates and boolean.
This is called StringlyTyped pattern and actually it makes code understanding painfully.

String typization

That’s why we should look on toString() as on data converter «as string».
And it should work only with Value classes and primitive datatypes wrappers, i.e. Integer, Boolean, Double, Date, Phone Numbers etc.

Important thing here is that this resulting string representation of value can be parsed verse to get an original value.

2. Serialization

In more common sense toString() it is a kind of serialization.
Even more, toString() can return JSON on CSV value.
But you should remember that deserialization is not granted by method contract.
That’s why you should use standard approach and implement Serializable interface.

But you still can use toString() as serialization for basic types that already contains written toString(), parse() and valueOf() methods.

3. Human readable representation of object

Another thing is when we need to show the object to a user. In this case it may be better to create another method called like a getDisplayName(), getTitle() or getCaption().

For example User class can contain getFullName() that return First Name and Second Name with space between them.

public class User {
   String firstName;
   String lastName;
   
   String getFullName() {
       return firstName + " " + lastName;
   }
}

Why it is better? First of all human readable names can be different and one string representation method may be not enough.

For example lets take a look on Facebook. In the private mail conversation between two users we can just write first name. At the public profile page we can display «First name + (nickname) Second name».

Also, usually this kind of display names can be localized. For example name of month or book title.

4. Log/Debug representation

In all other cases toString() used for logging or debug output. Just to make developer life easier.

The Groovy has a helpful @ToString annotation that generates this method in runtime.
For example class User can contain toString() method that return user login or email:

@ToString(includeNames = true, includes = 'email,firstName')
class User {
   String email
   String firstName
}

...

def user = new User(email: "admin@example.com", firstName: "Administrator")
assert user.toString() == "User(email:admin@example.com, firstName:Administrator)"

...
log.info("User ${user} logged in")

Here log.info() will call toString() method that is not good. I’m totally agree with Fabian and such method should be named toDebug() or dump(), but not toString().

Conclusion

Using this conventions may make your code better and safer.
I would be very thankful if you share conventions from your experience 🙂