Framework to populate a common field in unrelated classes

I am trying to write a framework for handling an interface with an external library and its API. As part of this, I need to fill out a header field that exists with the same name and enter into each of the many (70ish) possible message classes. Unfortunately, instead of each message class being derived from a common base class that will contain a header field, each of them is completely separate.

As an example of a toy:

public class A { public Header header; public Integer aData; } public class B { public Header header; public Long bData; } 

If they designed them, where A and B are derived from some base class containing the header, I could simply do:

 public boolean sendMessage(BaseType b) { b.header = populateHeader(); stuffNecessaryToSendMessage(); } 

But since it stands, Object is the only general class. The various options that I thought of would be as follows:

  • A separate method for each type. This will work and be fast, but code duplication will be depressingly wasteful.
  • I could subclass each of the types and provide them with an implementation of a common interface. While this will work, creating 70+ subclasses and then changing the code to use them instead of the original messaging classes is just too much of a bridge.
  • Reflection. Workable, but I expect it to be too slow (performance is a concern here).

Given them, a separate method for each seems to be the best, but I would like to have a better option.

+4
source share
3 answers

I offer you the following. Create a set of interfaces that you would like to have. for instance

 public interface HeaderHolder { public void setHeader(Header header); public Header getHeader(); } 

I would like your classes to implement them, i.e. you like that your class B is defined as

class B implements HeaderHolder {...}

Unfortunately, this is not the case. Now the problem!

Create facade:

 public class InterfaceWrapper { public <T> T wrap(Object obj, Class<T> api) {...} } 

You can implement it at this stage using a dynamic proxy. Yes, dynamic proxy uses reflection, but forget about it right now.

Once you're done, you can use InterfaceWrapper as follows:

 B b = new B(); new IntefaceWrapper().wrap(b, HeaderHolder.class).setHeader("my header"); 

As you can see now, you can set the headers in any class you want (if it has the corresponding property). Once you are done, you will be able to test your effectiveness. If and only if the use of reflection in a dynamic proxy is the bottleneck of the implementation change for code generation (for example, based on user annotation, package name, etc.). There are many tools that can help you do this, or, alternatively, you can implement this logic yourself. The fact is that you can always change the implementation of IntefaceWrapper without changing another code.

But avoid premature optimization. Reflection works very efficiently these days. Sun / Oracle worked hard to achieve this. They, for example, create classes on the fly and cache them to make reflection faster. Therefore, probably, taking into account the full flow, the reflecting call does not take too much time.

+2
source

The only library I know can do this is Dozer . It uses reflection, but the good news is that it will be easier to test if it is slower than writing your own reflection code to find that it is slow.

By default, dozer will call the same getter / seters on two objects, even if they are completely different. However, you can configure it in much more complex ways. For example, you can also specify that it access fields directly. You can provide it with your own converter for converting Maps to a list, something like this.

You can simply take one filled instance, or perhaps even your own BaseType and say: dozer.map(baseType, SubType.class);

+1
source

How about dynamically creating these 70+ subclasses during your project build? Thus, you do not need to support 70+ source files, while maintaining the benefits of this approach from your second bullet.

+1
source

Source: https://habr.com/ru/post/1481231/


All Articles