About Yoav Abrahami

Yoav is the Chief Architect at Wix.com, working with developers and operations to build the company's future products as well as accelerating and improving development processes.

Explicit Implicit Conversion

One of the most common pattern we use on our day to day is converting objects from one type of object to another. The reasons for that are varied; one reason is to distinguish between external and internal implementations, another reason would be to enrich incoming data with additional information or to filter out some aspects of the data before sending it over to the user. There are several approaches to achieve this conversion between objects:
 
 
 
 
 

  1. The Naïve Approach
  2. Add your converter code to the object explicitly:

    case class ClassA(s: String)
    
    case class ClassB(s: String) {
       def toClassA = ClassA(s)
    }

    While this is the most straightforward and obvious implementation, it ties ClassA and ClassB together which is exactly what we want to avoid.

  3. The fat belly syndrome
  4. When we want to convert between objects, the best way is to refactor the logic out of the class, allowing us to test it separately but still use it on several classes. A typical implementation would look like this:

    class SomeClass(c1: SomeConverter, c2: AnotherConverter, ...., cn, YetAnotherConverter) {
    ...........
    }

    The converter itself can be implemented as a plain class, for example:

    enum CustomToStringConverter {
    
        INSTANCE;
    
        public ClassB convert(ClassA source) {
            return new ClassB(source.str);
        }
    }

    This method forces us to include all the needed converters for each class that requires these converters. Some developers might be tempted to mock those converters, which will tightly-couple their test to concrete converters. for example:

    // set mock expectations
       converter1.convert(c1) returns c2
       dao.listObj(c2) returns List(c3)
       converter2.convert(c3) returns o4
    
       someClass.listObj(o0) mustEqual o4

    What I don’t like about these tests is that all of the code flows through the conversion logic and in the end you are comparing the result returned by some of the mocks. If for example one of the mock expectation of the converters doesn’t exactly compare the input object and a programmer will not match the input object and use the any operator, rendering the test moot.

  5. The Lizard’s Tail
  6. Another option is to use with Scala is the ability to inherit multiple traits and supply the converter code with traits. Allowing us to mix and match these converters. A typical implementation would look like this:

    class SomeClass extends AnotherClass with SomeConverter with AnotherConverter..... with YetAnotherConverter {
      ...............
    }

    Using this approach will allow us to plug in the converters into several implementations while removing the need (or the urge) to mock conversion logic in our tests, but it raises a design question – is the ability to convert one object to another related to the purpose of the class? It also encourages developers to pile up more and more traits into a class and never remove old unused traits from it.

  7. The Ostrich way
  8. Scala allows us to hide the problem and use implicit conversions. This approach allows us to actually hide the problem. An implementation would now look like this:

    implicit def converto0too2(o0: SomeObject): AnotherObj = ...
    implicit def convert01to02(o1: AnotherObject): YetAnotherObj = ...
    
    def listObj(o0: SomeObj): YetAnotherObj = dao.doSomethingWith(entity = o0)

    What this code actually does is converting o0 to o1 because this is what listObj needs. When the result returns o1 and implicitly convert it to o2. The code above is hiding a lot from us and leaves us puzzled if the tooling doesn’t show us those conversions. A good use case in which implicit conversions works is when we want to convert between object that has the same functionality and purpose. A good example for those is to convert between Scala lists and Java lists, both are basically the same and we do not want to litter our code in all of the places where we convert between those two.

To summarize the issues we encountered:

  1. Long and unused list of junk traits or junk classes in the constructor.
  2. Traits that doesn’t represent the true purpose of the class.
  3. Code that hides its true flow. To solve all of these, Scala has created a good pattern with the usage of implicit classes.

To write conversion code we can do something like this:

object ObjectsConveters {

implicit class Converto0To1(o0: SomeObject) {
   def asO1: AnotherObject = .....
}

implicit class Converto1To2(o0: AnotherObject) {
   def asO2With(id: String): YetAnotherObject = .....
}

Now our code will look like this:

import ObjectsConveters._

def listObj(o0: SomeObj): YetAnotherObj = listObj(o0.asO1).asO2With(id = "someId")

This approach allows us to be implicit and explicit at the same time. From looking at the code above you can understand that o0 is converted to o1 and the result is converted again to o2. If the conversion is not being used, the IDE will optimize the imports out of our code. Our tests won’t prompt us to mock each converter, resulting in specifications which explain the proper behavior of the code flow in our class. Note that the converter code is tested elsewhere. This approach allows us to write more readable test on other spots of the code. For example, in our e2e tests we reduce the number of objects we define:

"some API test" in {
   callSomeApi(someId, o0) mustEqual o0.aso2With(id = "someId")
}

This code is now more readable and makes more sense; we are passing some inputs and the result matches the same objects that we used in our API call.

Reference: Explicit Implicit Conversion from our JCG partner Noam Almog at the Wix IO blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

Leave a Reply


four + 6 =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close