Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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...

like image 782
Margaret Avatar asked Oct 18 '22 20:10

Margaret


1 Answers

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.

like image 164
ChiefTwoPencils Avatar answered Oct 21 '22 15:10

ChiefTwoPencils