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...
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With