Margaret
Margaret

Reputation: 105

Java - cast to an interface, then find out what the casted type is

I am struggling a bit with class casting. Let me set the scene. I have java server code that uses a service and orchestrator layer. A request comes into the service layer in a bean format (java class aligned with the front end view), and then i have a bunch of domainBeanMapper classes which take a bean format object and translate it to a domain format object. Eg UserBean has a dateOfBirth represented by a string, while User has the dateOfBirth represented by a Date so the UserMapper.java will make the date string into a date object. So for each object in the system i have a *.java, *Bean.java and *Mapper.java (User.java, UserBean.java, userMapper.java).

in applicationContext i hold the relationship from each object to their mapper, like this:

<util:map id="domainBeanMappers">   
    <entry key="UserBean" value-ref="userMapper" />
    <entry key="User" value-ref="userMapper" />
.....

and then i define the mapper:

<bean id="userMapper" class="com.me.mapping.UserMapper" parent="baseDomainBeanMapper"/>

I call the domain bean mappers like this from my service layer:

UserBean userBean = (UserBean) getDomainBeanMapper().mapDomainToBean(user);

In the run of this code I find the mapper object that I want like this:

    DomainBeanMapper mapper = findApplicableMapper(myObject.getClass().getName());
    if (mapper == null) {
        mapper = findApplicableMapper(myObject.getClass().getSimpleName());
    }

where findApplicableMapper works like this:

private DomainBeanMapper findApplicableMapper(String string) {
    return domainBeanMappers.get(string);
}

For the last few years, this has worked like a charm. For whatever object I want in the system i can easily pick out the relevant mapper and then translate from my bean format to domain format and vice-versa, based on the .getClass() call of any instance.

Now, I have a new requirement that is giving me trouble. I want to be able to translate from my User object to several sub-objects based on a parameter. So for some calls, i want just the id, firstName and lastName back. For other calls I want more fields, but still not the whole object, and then for some calls I want the whole object back like before. I don't want to go down the sub-objects path and end up with UserLight, UserLightWithName, UserLightWithNameButNoAddress, ... argh nightmare.

So instead I was hoping to create a bunch of interfaces representing "views". So the request comes in with the ViewType of Basic, and that means I want the user's personal details and address. So I wrote an interface called UserBasic, got User to implement it, and added a mapping from UserBasic to UserBasicMapper, and from UserBasicBean to UserBasicMapper, in the hope that I could make the translate call like this:

UserBasicBean restrictedUserReturn = (UserBasicBean) getDomainBeanMapper().mapDomainToBean((UserBasic)user);

but this doesn't work because getClass() always returns the instances class, not the interface that it has been cast to. I guess I can always add another paramater to the mapDomainToBean call which is the class that I want used, but the codebase is quite massive and I will need to touch on every call if i make that change.

So basically I'm looking for a way to cast an instance to an interface type and then find that interface type? Is this possible??

crosses fingers...

Upvotes: 5

Views: 306

Answers (4)

ChiefTwoPencils
ChiefTwoPencils

Reputation: 13930

Instead of making interfaces that the user implements, why not make proxy classes that represent the limited versions? For example,

class UserBasic {

    private User user;

    public UserBasic(User user) {
        this.user = user;
    }

    public String getFirstName() {
        return user.getFirstName();
    }
    ...
}

Then you can add a getUser() { return user; } to get the full instance back.

This way you should be able to keep everything else the same and make a trade-off for the class over interface.

Upvotes: 3

ikos23
ikos23

Reputation: 5354

Interface does not represent view - it defines a behaviour. I guess you need some kind of factory (ckech these links for inspiration https://en.wikipedia.org/wiki/Factory_method_pattern , https://sourcemaking.com/design_patterns/abstract_factory) here (or builder) If you say something about 'sub-objects' - try to extend UserBean class

class BaseUserBean extends UserBean {}
class AnotherUserBean extends UserBean {}

put the common stuff for all users into base class and something really specific to each of your sub-users let's say into children classes and then

 UserBean u = getDomainBeanMapper().mapDomainToBean(user);

...

//method mapToDomain should check your param and return the type you need
//ViewType can be a part of user or a separate param
UserBean mapDomainToBean(User user, ViewType vt) {
    if (vt == ViewType.BASE) {
      BaseUserBean obj = BaseUserBean ();
      // mapping here (set fields you need)
      return obj;
    }

    if (vt == ViewType.ANOTHER) {
      AnotherUserBean obj = AnotherUserBean ();
      // mapping here (set fields you need)
      return obj;
    }
    ...
}

Upvotes: 0

Krzysztof Cichocki
Krzysztof Cichocki

Reputation: 6414

You can make something like writing few methods that differ with the paramenter type, example:

public class Test
{

    public static void n(Number n) {
        System.out.println("Number");
    }

    public static void n(Integer n) {
        System.out.println("Integer");
    }

    public static void main(String[] args)
    {
        n(3); //will call the n(Integer n);
        n((Number)3); //will call the n(Number n);
    }
}

So yes, you can find out which type you have casted to by making multiple methods each taking proper parameter type and then processing it accordingly to type.

Upvotes: 0

Rajnikant Patel
Rajnikant Patel

Reputation: 571

I am not sure but you can use instanceof keyword to check which type of object it is.

Upvotes: 0

Related Questions