18

I've need an interface that assures me a certain method, including specific signature, is available. So far his is what I have:

public interface Mappable<M> {
    M mapTo(M mappableEntity);
}

The problem arises when a class should be mappable to multiple other entities. The ideal case would be this (not java):

public class Something implements Mappable<A>, Mappable<B> {
    public A mapTo(A someObject) {...}
    public B mapTo(B someOtherObject) {...}
}

What would be the best way to achieve this remaining as "generic" as possible?

4 Answers 4

17

This is, of course, not something you can do due to Type Erasure. At runtime, you have two methods public Object mapTo(Object), which obviously cannot coexist.

Unfortunately, what you are trying to do is simply beyond Java's type system.

Assuming your generic type is always a first class type, and not itself generic, you could achieve similar outward-facing behaviour by having the method mapTo(Object, Class), which would allow you to do runtime inspection of the given class and decide which behaviour to use. Obviously this is pretty inelegant--and will require manual casting of the return value--but I think it's the best you can do. If your generic types are themselves generic, then their generic parameters will be erased too and their Classes will be equal, so this method won't work.

However, I would point towards @Joachim's answer as well, this may be a case where you can split the behaviour out into separated components and sidestep the whole issue.

6

As you saw, you can't implement the same interface twice with different type parameters (because of erasure: at runtime they are the same interfaces).

Also, this approach violates the single responsibility principle: your class should focus on being a Something (whatever that means) and should not do the mapping to A or B in addition that task.

It sounds like you really should have a Mapper<Something,A> and a Mapper<Something,B>. This way each class has a single clearly-defined responsibility and you don't run into the problem of implementing the same interface twice.

3
  • Well, the idea is to let the class be responsible for "transforming" its contents to other objects. Then there's a dispatcher that handle them in a Class agnostic manner, therefore the generics requirement. I'll think a bit about extracting the logic, though that actually means I'm splitting the class in two, but they remain tightly coupled (access to field should be granted, modifying one most of the times imply modifying the other, etc)
    – estani
    Nov 25, 2013 at 9:45
  • 1
    @estani: yes, they are somewhat tightly coupled, but they have distinct responsibilities. Also think about this: when you introduce a new class C and you want Something to be mappable to that, then you'd need to modify Something, which is too much coupling. Just adding a new SoemthingToCMapper is less intrusive. Nov 25, 2013 at 9:50
  • 1
    +1 to this - generally speaking you should favour composition over inheritance if you're trying to achieve what the OP wants (in Java). Java 8 with default methods makes this even easier - but not everyone can jump on the bleeding edge yet :-). Nov 25, 2013 at 10:11
1

Given that's not allowed to implement multiples interfaces, you can consider the use of encapsulation. (example using java8+)

// Mappable.java
public interface Mappable<M> {
    M mapTo(M mappableEntity);
}

// TwoMappables.java
public interface TwoMappables {
    default Mappable<A> mapableA() {
         return new MappableA();
    }

    default Mappable<B> mapableB() {
         return new MappableB();
    }

    class MappableA implements Mappable<A> {}
    class MappableB implements Mappable<B> {}
}

// Something.java
public class Something implements TwoMappables {
    // ... business logic ...
    mapableA().mapTo(A);
    mapableB().mapTo(B);
}

Please check here for further info & more examples: How to make a Java class that implements one interface with two generic types?.

0
public interface IMappable<S, T> {
    T MapFrom(S source);
}

// T - target
// S - source

If you want to map User to UserDTO and map User to UserViewModel, then you'll need two separate implementations. Don't pile up all this logic into a single class - it doesn't make sense to do that.

Update to keep Joachim happy

public interface ITypeConverter<TSource, TDestination>
{
    TDestination Convert(TSource source);
}

But now we are in the Automapper realm (http://automapper.codeplex.com/wikipage?title=Custom%20Type%20Converters)

6
  • I don't think IMappable is a good name for something that maps other things. Mapper (or IMapper, if you must ;-)) is probably more correct. (By the way: no, that was not my downvote). Nov 25, 2013 at 9:49
  • I have taken what was in the question and prefixed with an I to highlight the fact it's an interface. I'm solving design problem as per question, as opposed to a naming problem.
    – CodeART
    Nov 25, 2013 at 9:52
  • 1
    sorry, but in my opinion one can not really "solve" a design problem and ignore naming. Design means understandable structures. Wrong naming is a problem to understanding. Nov 25, 2013 at 9:54
  • Update should put your mind at rest ;-)
    – CodeART
    Nov 25, 2013 at 10:02
  • 1
    @CodeART If I understood your answer correctly it implies "MapFrom" (which should be lowercased ;-) creates the object. In my case it's just filling information on an already created object.
    – estani
    Nov 25, 2013 at 10:06

Not the answer you're looking for? Browse other questions tagged or ask your own question.