I have this design which I self-proclaim to be Composite Pattern, though I'm not entirely sure about that. So I'm aksing for your statement on this.
This is the interface which collectively describes all of them
public interface DomainResourceBuilder<T extends DomainResource> {
T buildInsertion(T persistence, EntityManager entityManager) throws Exception;
T buildUpdate(T model, T persistence, EntityManager entityManger);
<E extends T> DomainResourceBuilder<E> and(DomainResourceBuilder<E> next);
}
This one describes DomainResourceBuilder as a pair
public abstract class AbstractDomainResourceBuilder<D extends
DomainResource> implements DomainResourceBuilder<D> {
#Override
public <E extends D> DomainResourceBuilder<E>
and(DomainResourceBuilder<E> next) {
return new CompositeDomainResourceBuilder<>(this, next);
}
private class CompositeDomainResourceBuilder<T extends D>
extends AbstractDomainResourceBuilder<T> {
private final DomainResourceBuilder<D> parentBuilder;
private final DomainResourceBuilder<T> childBuilder;
public
CompositeDomainResourceBuilder(DomainResourceBuilder<D>
parentBuilder,
DomainResourceBuilder<T> childBuilder) {
super();
this.parentBuilder = parentBuilder;
this.childBuilder = childBuilder;
}
#SuppressWarnings("unchecked")
#Override
public T buildInsertion(T model, EntityManager
entityManager) throws Exception {
return childBuilder.buildInsertion((T)
parentBuilder.buildInsertion(model, entityManager),
entityManager);
}
#SuppressWarnings("unchecked")
#Override
public T buildUpdate(T model, T persistence,
EntityManager entityManger) {
return childBuilder.buildUpdate(model, (T)
parentBuilder.buildUpdate(model, persistence,
entityManger), entityManger);
}
}
}
Concrete class plays the Leaf role
public class CustomerBuilder extends AbstractDomainResourceBuilder<Customer> {
#Override
public
Customer buildInsertion(Customer persistence, EntityManager entityManager) throws Exception {
return persistence;
}
#Override
public
Customer buildUpdate(Customer model, Customer persistence, EntityManager entityManger) {
return persistence;
}
}
Can I call this a Composite Pattern?
This is how I use it. Assumming I have the following hierarchy.
AbstractEntity
|___User
|___Customer
Now I want to implement different logics on each class, so with the design I'll create specific logic for those class and then ultimately compose them into one, which is still one of their kind. Something like this.
// group of objects
DomainResourceBuilder<AbstractEntity> abstractEntityBuilder = new AbstractEntityBuilder<>();
DomainResourceBuilder<User> userBuilder = new UserBuilder<>();
DomainResourceBuilder<Customer> customerBuilder = new CustomerBuilder<>();
// treat them as a whole (unify them all)
DomainResourceBuilder<Customer> compositeCustomerBuilder =
abstractEntityBuilder
.and(userBuilder)
.and(customerBuilder);
I do not think that it looks like Composite pattern as:
there is no a place where a group of objects that are treated the same way as a single instance of the same type of object.
In my view, it looks like it uses Builder pattern with generics that can treat hierarchy of entities.
UPDATE:
In my view it is not group of objects:
// group of objects
DomainResourceBuilder<AbstractEntity> abstractEntityBuilder = new AbstractEntityBuilder<>();
DomainResourceBuilder<User> userBuilder = new UserBuilder<>();
DomainResourceBuilder<Customer> customerBuilder = new CustomerBuilder<>();
If the above objects will be put in collection, then it can be called as group of objects. In my honour opinion, it is just object variables.
In the following lines of code, Fluent interface design pattern can be seen as methods can be chained:
// treat them as a whole (unify them all)
DomainResourceBuilder<Customer> compositeCustomerBuilder =
abstractEntityBuilder
.and(userBuilder)
.and(customerBuilder);
Let me show an example where group of objects can be treat as a whole.
The following literature has great examples and explanations:
this beautiful, very cool and interesting book by Eric Freeman
this article about composite pattern at wiki
this article about composite pattern at codemaze
Imagine you are building browser and you want to show controls. Your task is to show values of all of your controls placed in DOM browser.
So example code would look like this.
We need some base class for controls:
public abstract class ControlBase
{
protected string name;
protected string value;
public ControlBase(string name, string value)
{
this.name = name;
this.value = value;
}
public abstract string ShowValue();
}
and its operations:
public interface IControlOperations
{
void Add(ControlBase gift);
void Remove(ControlBase gift);
}
Then we create a composite control where we can have group of objects:
public class CompositeControl : ControlBase, IControlOperations
{
// group of objects
private List<ControlBase> _controls;
public CompositeControl(string name, string value)
: base(name, value)
{
_controls = new List<ControlBase>();
}
public void Add(ControlBase gift)
{
_controls.Add(gift);
}
public void Remove(ControlBase gift)
{
_controls.Remove(gift);
}
// group of objects can be treat as a whole
public override string ShowValue()
{
StringBuilder allValues = new StringBuilder();
Console.WriteLine($"{name} has the following values:");
foreach (var gift in _controls)
{
allValues.AppendLine(gift.ShowValue());
}
return allValues.ToString();
}
}
And our UI controls:
public class TextBox : ControlBase
{
public TextBox(string name, string value)
: base(name, value)
{
}
public override string ShowValue()
{
Console.WriteLine($"{name} has {value}");
return value;
}
}
public class CheckBox : ControlBase
{
public CheckBox(string name, string value)
: base(name, value)
{
}
public override string ShowValue()
{
Console.WriteLine($"{name} with value {value}");
return value;
}
}
And then we can call code like this:
var textBox_Phone = new TextBox("textBox_Phone", "1");
textBox_Phone.ShowValue();
Console.WriteLine();
//composite control
var divContainer = new CompositeControl("divContainer", string.Empty);
var textBox_Name = new TextBox("textBox_Name", "Joseph");
var textBox_Surname = new TextBox("textBox_Surname", "Albahari");
divContainer.Add(textBox_Name);
divContainer.Add(textBox_Surname);
Console.WriteLine($"Total values of this composite control " +
$"is: {divContainer.ShowValue()}");
Related
I have a Java enum A that I want to serialize with Hazelcast Portable interface.
To implement the PortableFactory associated with A I need to call an empty constructor to create an empty instance of A, but that is not possible when it comes to enum in Java.
What's the best way to implement a PortableFactory to serialize enum?
Here an example of what I'd like to achive:
public class MyPortableFactory implements PortableFactory {
#Override
public Portable create( int classId ) {
if (Foo.ID == classId) {
return new Foo(); //This is how you return normal class
} else if(MyEnum.ID == classId) {
return ???; //What should I return for the enum?
} else {
return null;
}
}
}
I have tried a workoround using a map to change the ids:
public enum MyEnum implements Portable {
Value1("1", "1", PortableIds.one),
Value2("2", "2", PortableIds.two),
Invalid("0", "0", PortableIds.InvalidID);
private String first;
private String second;
private Integer portableId;
public static final Map<Integer, MyEnum> mapPortableIdValues = new HashMap<>() {{
for (MyEnum myEnum : MyEnum.values()) {
put(myEnum.getPortableId(), myEnum);
}
}};
#Override
public int getFactoryId() {
return MyPortableFactory.FACTORY_ID;
}
#Override
public int getClassId() {
return portableId;
}
public class MyPortableFactory implements PortableFactory {
public static final int FACTORY_ID = 2;
#Override
public Portable create(int classId) {
if(mapPortableIdValues.containsKey(classId)){
return mapPortableIdValues.get(classId);
}
return null;
}
}
public interface PortableIds {
Integer one = 100;
Integer two = 101;
Integer InvalidID = 106;
}
But when I run my application I get the following exception:
com.hazelcast.nio.serialization.HazelcastSerializationException: Wrong Portable type! Generic portable types are not supported! Expected class-id: 100, Actual class-id: 106
at com.hazelcast.internal.serialization.impl.portable.DefaultPortableWriter.checkPortableAttributes(DefaultPortableWriter.java:174)
at com.hazelcast.internal.serialization.impl.portable.DefaultPortableWriter.writePortable(DefaultPortableWriter.java:147)
I think this use case is not a good fit for the design of the Portable serialization. The mechanism of Portable serialization instantiates an instance of a class and fills the fields with readPortable method at runtime. This is not really possible with enums.
I would suggest using a wrapper class to carry simply an integer enum tag or the name of the enum member as a string with Portable serialization.
This is a follow up to: my previous question
My following line of code does not work:
IAccount account = (AccountModel) new AccountRepository().getByEmail(emailaddress);
The returntype of ...getByEmail(...) is Model<Account>, and AccountModel extends Model<Account>.
Yet I get a java.lang.ClassCastException: models.Model cannot be cast to models.AccountModel when I test it. I know this is because every AccountModel is a Model<Account>, but not the other way around.
Is there any way how I can make sure that I can fix this (or work around it).
public class AccountRepository extends Repository<Account> {
public AccountRepository() {
super(Account.class);
}
public Model<Account> getByEmail(String emailAddress) {
return this.getCustomHqlSingle("FROM Account a WHERE a.emailAddress = '" + emailAddress + "'");
}
}
public abstract class Repository<T> implements Serializable {
protected final Model<T> getCustomHqlSingle(String hql) {
List<Model<T>> t = this.getCustomHqlList(hql);
if (t != null && !t.isEmpty()) {
return t.get(0);
} else {
return null;
}
}
protected final List<Model<T>> getCustomHqlList(String hql) {
Session session = SESSION_FACTORY.openSession();
try {
session.beginTransaction();
List<T> entities = session.createQuery(hql).getResultList();
List<Model<T>> result = new ArrayList<>();
for (T t : entities) {
result.add(this.getByEntity(t));
}
return result;
} finally {
session.close();
}
}
To the person that marked this question as duplicate, let me rephrase the following sentence from my question:
I know this is because every AccountModel is a Model<Account>, but
not the other way around.
To
I know this is because every Dog is an Animal, but not the other
way around.
You have to devise a method in which to convert a Model<Account> to an AccountModel. Taking the code from your other question you could add a constructor for this to the AccountModel class:
public class AccountModel extends Model<Account> implements IAccount {
private static final AccountRepository REPOSITORY = new AccountRepository();
public AccountModel(Account entity) {
super(entity, REPOSITORY);
}
public AccountModel(Model<Account> model) { // <---
super(model._entity, REPOSITORY);
}
// Method implementations...
}
Then change your AccountRepository class to return an AccountModel from getByEmail:
public AccountModel getByEmail(String emailAddress) {
return new AccountModel(this.getCustomHqlSingle("FROM Account a WHERE a.emailAddress = '" + emailAddress + "'"));
}
Which uses the new constructor to convert the Model<Account> to an AccountModel.
There is another option. Rather than calling new Model<T>(...) in Repository, you could have implementing classes implement an abstract method that would return the desired Model type:
public abstract class Repository<T, R> implements Serializable
...
public Repository(Class<T> repositoryClass) {
if (!Repository._initiated)
setup();
this.cons = cons;
}
protected abstract R getModel(T entity, Repository<T> repo); // <--
Then somewhere in the factory methods:
public R getByFoo(...) {
...
T t = session.get(_repositoryClass, ...);
return getModel(t, this);
}
Where AccountRepository would return a new AccountModel:
public class AccountRepository extends Repository<Account, AccountModel> {
public AccountRepository() {
super(Account.class);
}
#Override
protected AccountModel getModel(Account entity, Repository<Account> repo) {
return new AccountModel(entity);
}
}
Since you say you understand why you get an error, let me try to explain something else about casting.
Except for some limited cases, the casting operator does not change the item being cast. Casting is an instruction to the compiler only, saying "My logic has guaranteed that the type of the cast object is different than the compiler can determine, so while you (the compiler) would tell me this is an error, I am certain that, at runtime, it will be fine. So don't give me an error".
It does NOT say "take this object and transform it into another, similar object". That operation is not possible in Java, thank heavens.
I have two unrelated java classes (only *.class, no *.java) like this:
public class Trick {
public String getName() { return "Jack"; }
public String trick() { ... }
}
and
public class Treat {
public String getName() { return "John"; }
public String treat() { ... }
}
and I would like to generate a sort of Proxy class at runtime that represents the union of both classes and forwards them to the respective instance, and maybe throw if that's not possible. I assume that can be done with cglib but I don't know where to start.
This is what I would like to do (pseudocode):
// prepare: generate a common interface
TrickOrTreat trickOrTreat = magic.createUnionInterface(Trick.class, Treat.class);
// use with concrete interface A:
Trick trick = new Trick();
TrickOrTreat proxyA = magic.createProxy(trickOrTreat.class, trick);
System.out.println("trick name: " + proxyA.getName());
// use with concrete interface B:
Treat treat = new Treat();
TrickOrTreat proxyB = magic.createProxy(trickOrTreat.class, treat);
System.out.println("treat name: " + proxyB.getName());
Or something to that effect. I would like to do it completely dynamically, probably cglib-based? If thats not possible I would do it with a code generation step in between?
If you are willing to trade in cglib, you can do this with Byte Buddy. I typically refuse to call it magic but here you go:
class Magic {
Class<?> createUnionInterface(Class<?> a, Class<?> b) {
DynamicType.Builder<?> builder = new ByteBuddy().makeInterface();
Set<MethodDescription.SignatureToken> tokens = new HashSet<>();
for (MethodDescription m : new TypeDescription.ForLoadedType(a)
.getDeclaredMethods()
.filter(ElementMatchers.isVirtual())) {
tokens.add(m.asSignatureToken());
builder = builder.defineMethod(m.getName(),
m.getReturnType(),
m.getModifiers()).withoutCode();
}
for (MethodDescription m : new TypeDescription.ForLoadedType(b)
.getDeclaredMethods()
.filter(ElementMatchers.isVirtual())) {
if (!tokens.contains(m.asSignatureToken())) {
builder = builder.defineMethod(m.getName(),
m.getReturnType(),
m.getModifiers()).withoutCode();
}
}
return builder.make()
.load(Magic.class.getClassLoader())
.getLoaded();
}
Object createProxy(Class<?> m, final Object delegate) throws Exception {
return new ByteBuddy()
.subclass(m)
.method(new ElementMatcher<MethodDescription>() {
#Override
public boolean matches(MethodDescription target) {
for (Method method : delegate.getClass()
.getDeclaredMethods()) {
if (new MethodDescription.ForLoadedMethod(method)
.asSignatureToken()
.equals(target.asSignatureToken())) {
return true;
}
}
return false;
}
}).intercept(MethodDelegation.to(delegate))
.make()
.load(Magic.class.getClassLoader())
.getLoaded()
.newInstance();
}
}
Note that you cannot reference a runtime-generated type at compile-time. This is however a given constraint with runtime code generation.
Magic magic = new Magic();
Class<?> trickOrTreat = magic.createUnionInterface(Trick.class, Treat.class);
Trick trick = new Trick();
Object proxyA = magic.createProxy(trickOrTreat, trick);
System.out.println("trick name: " + trickOrTreat.getDeclaredMethod("getName").invoke(proxyA));
Treat treat = new Treat();
Object proxyB = magic.createProxy(trickOrTreat, treat);
System.out.println("trick name: " + trickOrTreat.getDeclaredMethod("getName").invoke(proxyB));
You can overcome this by generating your TrickOrTreat class prior to runtime such that you can reference the type at runtime.
As for the suggested union-type approach, this would require you to have at least one class to be an interface type as Java does not support multiple inheritance.
If you need functionality of both classes/interfaces you can use
public <TT extends Trick & Treat> void process(TT thing){
//...
}
edit:
Implement new Interface MyProxyHandler
public interface MyProxyHandler {}
Extend it with interfaces of classes say TreatInterface and TrickInterface
Create class ProxyManager that implements java.lang.reflect.InvocationHandler
public abstract class ProxyManager<T extends MyProxyHandler> implements InvocationHandler {
protected static String LOCK_OBJECT = new String("LOCK");
protected T proxyHandler;
protected List<T> handlers = new ArrayList<>();
#SuppressWarnings("unchecked")
public ProxyManager(Class<T> _clazz) {
proxyHandler = (T) Proxy.newProxyInstance(_clazz.getClassLoader(), new Class[]{_clazz}, this);
}
public T getProxy() {
return proxyHandler;
}
public List<T> getHandlers() {
return handlers;
}
public void setHandlers(List<T> handlers) {
this.handlers = handlers;
}
public boolean registerHandler(T handler) {
synchronized (LOCK_OBJECT) {
boolean add = true;
for (T item : this.handlers) {
if (item.getClass().equals(handler.getClass())) {
add = false;
}
}
if (add)
this.handlers.add(handler);
return add;
}
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String result = "";
for (MyProxyHandler handler : getHandlers()) {
try {
//I recommend that methods returns some enum like HANDLED/NOTHANDLED
result = (String) method.invoke(handler, args);
if (result.equals("Some flag"))
break;
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
return result;
}
}
Extend that class with your concrete class
public class TreatTrickProxyManager<T extends TreatInterface & TreatInterface> extends ProxyManager<T> {
public TreatTrickProxyManager(Class<T> _clazz) {
super(_clazz);
}
}
In your bussines logic class get an instance of TreatTrickProxyManager
In your method
public void retrieveSomeData(){
((TreatTrickProxyManager)getTreatTrickProxyManager().getProxy()).someMethodInvocation()
}
i have a domain class(DB):
public class PersonDoamin {
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
i also have model class:
public class PersonBean extends PersonDoamin {
}
so when i go to DAOImpl class and query for List and transfer this list to List and return to users as i have interface method for List getAllPerson(). so my questions is here when i transfer all data from List. Here i have some utility method that copies from one bean to another like this:
List<PersonDoamin> list = PersonDAO.getAllPersons();
List<PersonBean> pbList = new ArrayList<PersonBean>();
/* this below logic is pretty much in the all DAO impl*/
for(PersonDoamin p : list){
PersonBean pb = new PersonBean();
CopyHelper.copyBean(p, pb);
pbList.add(pb);
}
return pbList;
can we replace the looping and copying and adding to another list and returning part with somekind of generic method which will take any object two list and loop thorugh one and add it to another passed List parameter and return it. something like below which is not perfect right now:
public static <T> List<T> listToArray(List<T> list,List<T> list2) {
for(T element : list){
list2.add(element);
}
return list2;
}
public static void main(String[] args) {
List<PersonDoamin> personList = new ArrayList<PersonDoamin>();
PersonDoamin p = new PersonDoamin();
p.setName("aj");
p.setAge("25");
personList.add(p);
List<PersonBean> personBeansToReturn = new ArrayList<PersonBean>();
Test.listToArray(personList , personBeansToReturn );
}
A bit off topic, your design seems a bit weird that you have "Domain" class and "Bean" class and have "Bean" extends "Domain"...
Anyway, come back to your question, what you are trying to do is:
You have a List<Domain>
You want to transform each Domain in the List into a Bean (by use of some util method)
Put the resulting Beans into a list and return
Let's go through it step by step.
(by the way, the listToArray method you wrote does not align with your original loop as it does not do the transformation (point 2). I guess it is typo?)
(all psuedo code as I don't have environment on hand to make it compile. Concept should be correct I guess)
Step 1: Util method for Person
One biggest problem of your original util method is that, it is illegal to put a Parent object instance to a List of Child (it should be easy to figure why by yourself).
The util method should look like this:
List<PersonBean> toBeans(List<PersonDomain> domains) {
List<PersonBean> beans = new ArrayList<>(domains.size());
for (PersonDomain domain: domains) {
PersonBean bean = new PersonBean();
CopyHelper.copyBean(domain, bean);
beans.add(bean);
}
return beans;
}
Step 2: Make it generic
The problem above is that it only works for Person. If you want to make it generic, you will also need to provide the function to transform Domain to Bean:
(Assume you are using Java8, should be trivial to make your own interface if you are using older version)
<D,B> List<B> toBeans(List<D> domains, Function<B,D> mapper) {
List<PersonBean> beans = new ArrayList<>(domains.size());
for (PersonDomain domain: domains) {
beans.add(mapper.apply(domain));
}
return beans;
}
so that you can use it by:
return toBeans(personDomains, (domain) -> {
PersonBean bean = new PersonBean();
CopyHelper.copyBean(domain, bean);
return bean;
});
(You may consider wrap the function if in most case you are going to use the CopyHelper way)
<D,B> List<B> toBeansByBeanCopy(List<D> domains, Class<B> beanClass) {
return toBeans(domains, (domain)-> {
B bean = beanClass.newInstance();
CopyHelper.copyBean(domain, bean);
return bean;
});
}
so that you can use it as
return toBeansByBeanCopy(personDomains, PersonBean.class);
Step 3: Java has done it for you
Actually what you are trying to do above, it is already provided by Java in Java 8. You can simply do:
return personDomains.stream()
.map(d -> {
PersonBean bean = new PersonBean();
CopyHelper.copyBean(domain, bean);
return bean;
})
.collect(Collectors.toList());
You may write a little method to use in the lambda expression if it is the standard way.
return personDomains.stream()
.map(BeanMapper.mapper(PersonBean.class))
.collect(Collectors.toList());
(Leave the implementation as your exercise)
If you're looking for a way to call new on a generic type, you can, sort of. You have to use reflection and call newInstance on the Class object. I don't know if this is going to be feasible for you.
Also, I don't see anyway of realistically implementing your bean copy method without using some heavy reflection as well. In the example below I faked by just casting to the required classes.
public class GenericCopyTest
{
public static void main( String[] args ) throws Exception
{
List<PersonDoamin> personList = new ArrayList<PersonDoamin>();
PersonDoamin p = new PersonDoamin();
p.setName( "aj" );
p.setAge( "25" );
personList.add( p );
List<PersonBean> personBeansToReturn = new ArrayList<PersonBean>();
copyAndDowncast( personList, personBeansToReturn, PersonBean.class );
System.out.println( personBeansToReturn );
}
public static <T,U extends T> List<U> copyAndDowncast( List<T> from,
List<U> to, Class<U> type )
throws InstantiationException, IllegalAccessException
{
for( T element : from ) {
U nu = type.newInstance();
copyBean( element, nu );
to.add( nu );
}
return to;
}
private static <X,Y extends X> void copyBean( X from, Y nu ) {
((PersonBean)nu).setName( ((PersonDoamin)from).getName() );
((PersonBean)nu).setAge( ((PersonDoamin)from).getAge() );
}
}
class PersonDoamin {
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
#Override
public String toString()
{
return "PersonDoamin{" + "name=" + name + ", age=" + age + '}';
}
}
class PersonBean extends PersonDoamin {
#Override
public String toString()
{
return "PersonBean{" + getName() + ',' + getAge()+ '}';
}
}
Output:
run:
[PersonBean{aj,25}]
BUILD SUCCESSFUL (total time: 0 seconds)
Why not just use addAll() for this? It does what you're trying to do, and it's already part of the system library.
Remember you can add a PersonBean to a PersonDomain list, but not the other way around.
public class GenericCopyTest
{
public static void main( String[] args ) {
List<PersonDoamin> personList = new ArrayList<PersonDoamin>();
List<PersonBean> personBeansToReturn = new ArrayList<PersonBean>();
personList.addAll( personBeansToReturn );
personBeansToReturn.addAll( personList ); // <-- FAILS
// No suitable method found
}
}
class PersonDoamin {}
class PersonBean extends PersonDoamin {}
If you want to put more than one bean class in the same list,
how about creating the list with parent class PersonDoamin , and then, you can store both PersonDoamin and PersonBean classes.
public static void main(String[] args) {
List<PersonDoamin> personList = new ArrayList<PersonDoamin>();
PersonDoamin p = new PersonDoamin();
p.setName("aj");
p.setAge("25");
personList.add(p);
// Changed here. PersonBean => PersonDoamin
List<PersonDoamin> personBeansToReturn = new ArrayList<PersonDoamin>();
Test.listToArray(personList, personBeansToReturn);
// also you can insert PersonBean into the list
personBeansToReturn.add(new PersonBean());
}
Let's say I have these set of POJO class that implement an interface but there are no common attributes here.
public interface MainIfc {}
class Ifc1 implements MainIfc {
private String a1;
public String getA1() {
return a1;
}
public void setA1(String a1) {
this.a1 = a1;
}
}
class Ifc2 implements MainIfc {
private String x1;
private String x2;
public String getX1() {
return x1;
}
public void setX1(String x1) {
this.x1 = x1;
}
public String getX2() {
return x2;
}
public void setX2(String x2) {
this.x2 = x2;
}
}
And in conjunction with these POJO classes I have a couple of methods which I can use to retrieve the type of POJO being returned based on another value and the actual POJO with values.
public class GetIfc {
public Class getIfcType(int code) {
if (code==1)
return Ifc1.class;
else
return Ifc2.class;
}
public MainIfc getIfc(int code) {
if (code==1) {
Ifc1 thisIfc = new Ifc1();
thisIfc.setA1("Ifc1");
return thisIfc;
} else {
Ifc2 thisIfc = new Ifc2();
thisIfc.setX1("Ifc2");
thisIfc.setX2("Ifc2");
return thisIfc;
}
}
}
Is there a way using which I can read the concrete POJO safely in my code and use the getters/setters? I have gone through quite a few questions which provide answers based on Reflection but that isn't working for me. The getters/setters aren't visible and when I call .getClass() on the returned Object I see it is the MainIfc interface.
The design problem I am trying to solve pertains to a REST API automation framework that I am trying to design. Basically I have a ClientResponse parser which will send back the POJO I am looking for. But I don't want the folks writing the test cases to worry about the type of POJO that is returned. So I was thinking I could return the type and the instantiated POJO so I get the values but I am troubled over how to achieve this dynamically.
Try this code. Maybe this will return all the methods in class as well as methods inherited from Object class.
public static void main(String[] args) throws ClassNotFoundException {
GetIfc getIfc=new GetIfc();
MainIfc clas1s=getIfc.getIfc(1);
Class class1= clas1s.getClass();
System.out.println(class1);
Method[] mem= class1.getMethods();
for(Method mmm : mem) {
System.out.println(mmm.getName());
}
}
Do consumers of MainIfc actually need the POJOs, or just the data inside of them?
It might be cleaner design if MainIfc declares a method or two that exposes the data that its consumers will need. Your POJOs can then implement the methods that the MainIfc interface declares. Or you can build a wrapper class for each POJO that conforms it to the interface, if you want to keep the concerns of implementing your interface separate from your POJOs.
Ideally an interface should expose a few methods that can be used to interact with any class which implements it and no one should need to know about the underlying POJOs/implementation.
public interface MainIfc {
public Hash getAttributes();
public setAttributes(Hash attributes);
}
class Ifc1 implements MainIfc {
private String a1;
public String getA1() {
return a1;
}
public void setA1(String a1) {
this.a1 = a1;
}
public Hash getAttributes() {
// return a hash with data that MainIfc consumer will need from this POJO
}
public setAttributes(Hash attributes) {
// copy hash attributes to corresponding POJO fields
}
}
class Ifc2 implements MainIfc {
private String x1;
private String x2;
public String getX1() {
return x1;
}
public void setX1(String x1) {
this.x1 = x1;
}
public String getX2() {
return x2;
}
public void setX2(String x2) {
this.x2 = x2;
}
public Hash getAttributes() {
// return a hash with data that MainIfc consumer will need from this POJO
}
public setAttributes(Hash attributes) {
// copy hash attributes to corresponding POJO fields
}
}
It sounds to me like you're trying to do something rather illogical. Strategy Pattern or Abstract Factory might be a good fit for your requirement, but at the moment I don't quite understand what exactly it is you're trying to achieve. You should definitely not be conditionally casting and calling different methods on these classes. If you really want to continue on this path, I would suggest going with reflection, if not an option, and you need the flexibility, I'd probably go with a Map of some kind.
But I would definitely rethink your design if at all possible.
Try this piece of code, I don't know if I fully understand your requirement but based on my understanding I think below code would do the trick.
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
GetIfc getIfc = new GetIfc();
MainIfc clas1s = getIfc.getIfc(1);
Field[] fields = clas1s.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
Class fieldClasslasse = field.getType();
if (field.getModifiers() == Modifier.PRIVATE) {
// you need to check fieldClass, if it is boolean then initials of the getter could be 'is' instead of 'get'
String methodNameGet = "get" + Character.toUpperCase(field.getName().charAt(0))
+ field.getName().substring(1);
String methodNameSet = "set" + Character.toUpperCase(field.getName().charAt(0))
+ field.getName().substring(1);
Method methodGet = clas1s.getClass().getDeclaredMethod(methodNameGet, null);
Object value = methodGet.invoke(clas1s, null);
if (value != null && value instanceof String) {
String valueUpper = ((String)value).toUpperCase();
Class[] cArg = new Class[1];
cArg[0] = String.class;
Method methodSet = clas1s.getClass().getDeclaredMethod(methodNameSet, cArg);
Object[] var = new Object[1];
var[0] = valueUpper;
methodSet.invoke((Object) clas1s, var);
}
}
}
}
A little explanation about above code : Get all the fileds of the object and check if is a private property, if yes then it must have a public getter and setter, guess their name based on java convention, call the getter, get the value, check if it is a instance of String class, if yes make it UPPERCASE then call setter to set new value.