Design generic interface for data object used throughout a service - java

Been migrating over some legacy code and I came across this.
#Getter
#Setter
public class CollectedData
{
SkillResponse skills;
TrendingResponse storyMatch;
Map<String, String> slotData;
Map<String, String> slotDataSecondSource;
Boolean hasSlots;
Boolean hasSlotsSecondSource;
KnowledgeRequest request;
}
Since I've been using java 8 and accustomed to streams, I started to restructure this response class as ..
#Getter
#Setter
public class CollectedData
{
List<DataSupplierResponse> dataSupplierResponses;
Metadata metadata;
}
Where DataSupplierResponse was to be a defined interface like so..
public interface DataSupplierResponse<T>
{
DataSupplierType getDataSupplierType();
T getSupplierResponse();
}
Implementation Example:
public class DataSupplierResponseImpl implements DataSupplierResponse<TrendingResponse>
{
private TrendingResponse mTrendingResponse;
public DataSupplierResponseImpl(
TrendingResponse trendingResponse)
{
mTrendingResponse = trendingResponse;
}
#Override
public DataSupplierType getDataSupplierType()
{
return DataSupplierType.TRENDING_STORY;
}
#Override
public TrendingResponse getSupplierResponse()
{
return mTrendingResponse;
}
}
The goal is to run certain predicates depending on the CollectedData.
Optional<DataSupplierResponse> first = data.getDataSupplierResponses().stream()
.filter(res -> res.getDataSupplierType().equals(DataSupplierType.TRENDING_STORY))
.findFirst();
This would need a cast in order to get the right object. It returns Object
TrendingResponse match = first.get().getSupplierResponse();
Thus when I started refactoring, I assumed to solve this issue of data being available by creating the generic interface that returns different data. To make this code work, I would have to cast the return object of getSupplierResponse which defeats the purpose of using generics. I need to make this Data Carrier object as clean and beautiful as possible for my own sake. Any ideas how I should structure these classes, and/or how to use generics to solve this problem.
EDIT: I know the StackOverflow community likes to enforce objective, concrete answers but where else to go to for design questions?

You have to specify the List in CollectedData also with generics. E.g:
List<DataSupplierResponse> dataSupplierResponse;
should actually be:
List<DataSupplierResponse<YourType>> dataSupplierResponse;
where YourType corresponds to the type of the response. That is because when using a RawType (a generic class without actually specifiying a generic) all Generic information for that class is eliminated. That's why it is returning Objects and you have to manually cast it.

Unless used in other places, I'd get rid of the enumeration type DataSupplierType as the classes TrendingResponse (and others) already provide a discrimination criteria.
(Also keep in mind that enums are full classes)
The perfect response to this would have you implement a basic type for your response, e.g:
interface Response {
int getScore(); // implement in subclasses
String getName(); // implement in subclasses
}
class TrendingResponse implements Response {}
class SkillResponse implements Response {}
class OtherResponse implements Response {}
but this is not strictly necessary.
At this point just a generic wrapper class would be enough (no need to have a base interface and extend it for each type of response):
class DataSupplierResponse<T extends Response> {
private T t;
public DataSupplierResponse(final T t) {
this.t = t;
}
public T getSupplierResponse() {
return this.t;
}
}
This would allow you to call:
Optional<DataSupplierResponse<?>> first = data.responses
.stream()
.filter(response -> TrendingResponse.class.isAssignableFrom(response.getClass()))
.findFirst();
first.ifPresent( o -> o.getSupplierResponse().getScore() );
or simply
Optional<?> first = data.responses
.stream()
.filter(response -> TrendingResponse.class.isAssignableFrom(response.getClass()))
.map(r -> r::getSupplierResponse)
.findFirst();
Even without the base interface Response (which is useful only for defining common behavior in your responses), your class DataSupplierResponse<T> wouldn't need the enumeration type.

Related

Java Hibernate: What would be the better design to get rid of casting

I use Hibernate for persistence.
Suppose I have an entity which contains information about the document and the necessary information for producing it (either printing or sending by email). Just like this:
The problem here is that DocumentInformation holds reference to abstract class DocumentProductionConfiguration not to the subclasses DocumentPrintConfiguration or DocumentEmailConfiguration.
So when I actually need to get appropriate configuration I have two choices: either use instanceof + casting or use visitor pattern to trick Java so that it would actually understand in the runtime which configuration it is dealing with.
Using casting:
public class XmlBuilder{
public XMLMessage buildXmlMessage(DocumentInformation documentInformation){
if(documentInformation.getDocumentProductionConfiguration() instanceOf DocumentPrintConfiguration){
DocumentPrintConfiguration printConfig = (DocumentPrintConfiguration) documentInformation.getDocumentProductionConfiguration();
XMLMessageConfig xmlConfig = handlePrintConfig(printConfig);
}
}
public XMLMessageConfig handlePrintConfig(DocumentPrintConfiguration printConfig){
....build that XMLMessageConfig....
}
}
Using visitor pattern:
I need to add a new interface for XmlBuilder to implement
public interface XmlBuilderVisitor<T> {
T handlePrintConfig(DocumentPrintConfiguration printConfig);
}
public class XmlBuilder implements XmlBuilderVisitor<XMLMessageConfig> {
#Override
public XMLMessageConfig handlePrintConfig(DocumentPrintConfiguration printConfig){
....build that XMLMessageConfig....
}
public XMLMessage buildXmlMessage(DocumentInformation documentInformation){
XMLMessageConfig xmlMessageConfig = documentInformation.getDocumentProductionConfiguration().buildConfiguration(this);
}
}
public abstract class DocumentProductionConfiguration{
public abstract <T> T buildConfiguration(XmlBuilderVisitor<T> visitor);
}
public class DocumentPrintConfiguration extends DocumentProductionConfiguration{
public <T> T buildConfiguration(XmlBuilderVisitor<T> visitor){
return visitor.handlePrintConfig(this);
}
}
Both of these solutions are kinda meh... The first one because it violates open-closed principle (I will need to always maintain these ifs...).
The second one in this sense is better: once you add new configuration, compiler will guide you through the process: first, you will need to implement appropriate method in the configuration itself, then in all the visitor classes. On the other hand, it is pretty awkward that I am basically passing service to the entity...
So I feel like I am treating symptoms rather than the problem. Maybe the design itself needs some changes? But I am not sure how it could be improved...
I would reccomend pushing the "handle" functionality into the DocumentProductionConfiguration and subclasses. So that the DocumentPrintConfiguration would contain a handle function that builds and returns a XMLMessageConfig. Then your XmlBuilder becomes:
public class XmlBuilder{
public XMLMessage buildXmlMessage(DocumentInformation documentInformation){
XMLMessageConfig xmlConfig = documentInformation.getDocumentProductionConfiguration().handle();
}
}

JAVA - forced to cast Objects in their own object to apply methods

I have a class collection<T> extends ArrayList()
the object lesCommandes is a collection of multiple Commandes
I stock 3 objects from the class Commandes in it and when i want to apply methods to one of them this.lesCommandes.get(1).xmlCommande() i need to cast it or it doesn't work ((Commande)this.lesCommandes.get(1)).xmlCommande()
class Collection<T> extends ArrayList{}
this.commande1=new Commande(1,10,"filet 1kg",1,"10-12-2015","10-01-2016","en cours");
this.commande2=new Commande(2,15,"filet 5kg",1,"11-11-2015","10-02-2016","livrée");
this.commande3=new Commande(3,20,"caisse 10kg",2,"12-10-2015","10-03-2016","livrée");
this.lesCommandes.add(0, commande1);
this.lesCommandes.add(1, commande2);
this.lesCommandes.add(2, commande3);
xml=((Commande)this.lesCommandes.get(1)).xmlCommande();
You have to extend ArrayList<Commande>, so the objects stored in it will remain of Commande type
First a few advices on design (if I may).
Don't use inheritance for composition.
extends means is a relationship, which is often abused: you can say a GroupOfOrders is a ListOfOrders and define the following (in this case it really means is implemented in terms of):
public GroupOfOrders extends List<Order> {...}
But, it is generally better to define this relation in terms of composition and use the List<T> for the (hidden) implementation.
Why? - because,
you may want to have a hierarchy of GroupOfOrders and you can only extends once,
when you extends you inherit all the public and protected members from the super class. in your case, these methods are not part of the (functional) domain. You may not really want to allow clients of your class to apply any methods from List<T>.
If you decide to change the implementation and say that a GroupOfOrders is actually better implemented with a Set<T>, meaning you don't authorise the duplicate Order into a GroupOfOrders, you can easily do it if you don't extends 'List. It can be very difficult if you extendsList` and client classes use methods from it all over the code - it can be even worse if there are external clients from whom you don't control the code and usage of your class.
Just for the example, I defined the Order class (commande in english is order - It's just a matter of sharing with people, I don't mean you need to translate the code)
public class Order {
// properties, constructor...
public OrderResult executeOrder() {
// just do it
}
public String asXML() {
// generate the order as an XML string
}
}
public class GroupOfOrders {
private List<Order> orders = new ArrayList<>();
public void addOrder(Order o) {
// do some checking on order
orders.add(order);
}
public GroupedOrderResult executeAllOrders() {
GroupedOrderResult result = new GroupedOrderResult();
for (Commande c : commandes) {
OrderResult res = c.executeOrder();
result.add(c, res);
}
return result;
}
List<Order> getOrders() { return orders; }
}
And maybe, somewhere else in the program, when you need to get each order as an XML string:
GroupOfOrders orders; // initialised with the different orders
for (Order o : orders.getOrders()) {
String xmlOrder = o.asXML();
// do what needs to be done with xmlOrder
}
You will note that there is nowhere a need to cast.
Second, a few comments on the code you provided:
class Collection<T> extends ArrayList{}
This doesn't make sense: an ArrayList already implements Collection interface. May be you mean you have
List<T> lesCommandes = new ArrayList<Commande>();
this.commande1=new Commande(1,10,"filet 1kg",1,"10-12-2015","10-01-2016","en cours");
this.commande2=new Commande(2,15,"filet 5kg",1,"11-11-2015","10-02-2016","livrée");
this.commande3=new Commande(3,20,"caisse 10kg",2,"12-10-2015","10-03-2016","livrée");
this.lesCommandes.add(0, commande1);
this.lesCommandes.add(1, commande2);
this.lesCommandes.add(2, commande3);
Just do
lesCommandes.add(commande1); etc..
The List<T>$add(T) will actually add at the end of the list and manage the size dynamically.
xml=((Commande)this.lesCommandes.get(1)).xmlCommande();
If lesCommandes is defined as I suggest and there is a xmlCommande() method in the Commande class, then just do
xml = lesCommandes.get(1).xmlCommande();

instantiate a specific subtype depending on the constructor argument

I've the case that I have four types of data objects:
class DataTypeAlpha extends DataType
class DataTypeBeta extends DataType
class DataTypeGamma extends DataType
class DataTypeDelta extends DataType
and four different TreeNode types from the GUI framework, each one specific to the wrapped DataType:
class AlphaTreeNode extends MyAppTreeNode
...
Now I often have the pattern that I have an instance of DataType and need a new instance of MyAppTreeNode. I see two solutions. Solution one:
class DataType {
// Instantiates and returns the appropriate MyAppTreeNode for this DataType
abstract MyAppTreeNode createTreeNode();
}
Solution two:
class MyAppTreeNode {
static MyAppTreeNode createTreeNodeForDataType(DataType dataType) {
if(dataType instanceOf DataTypeAlpha) return new AlphaTreeNode((DataTypeAlpha)dataType)
else if (dataType instanceOf DataTypeBety) return new BetaTreeNode((DataTypeBeta)dataType)
else if ...
else if ...
else throw new IllegalArgumentException();
}
}
Solution one uses polymorphism, is shorter and more "elegant". But I'd prefer that the DataType classes have no knowledge about the GUI framework that I use. Maybe I could even use two different GUI frameworks?
Do you see a third solution? I added the Guice tag to this question. Maybe there is some function in Guice or another dependency injection library that could help here?
Looking through similar questions:
Of course I will use the Factory Pattern for this, but inside the factory I'm still left with the question.
You might use a visitor inspired approach for this. As usual all DataType objects has an accept method, but as opposed to the normal visitor pattern, it does not traverse children and it will return a value. To avoid too much confusion, lets call object passed to accept for an operator instead of visitor. The trick is to make accept and operators return a generic type.
So the code will be something like this in the data model
public abstract class DataType {
public abstract <T> T accept(Operator<T> op);
}
public interface Operator<T> {
T operateAlpha(DataTypeAlpha data);
T operateBeta(DataTypeBeta data);
...
}
public class DataTypeAlpha extends DataType {
public <T> T accept(Operator<T> op) {
return op.operateAlpha(this);
}
}
....
and in the GUI you will have
public class TreeNodeFactory implements Operator<MyAppTreeNode> {
public MyAppTreeNode operateAlpha(DataTypeAlpha data) {
return new AlphaTreeNode(data);
}
...
}
public class MyAppTreeNode {
static TreeNodeFactory factory = ...;
static MyAppTreeNode createTreeNodeForDataType(DataType dataType) {
return dataType.accept(factory);
}
}
So the short, simple answer is that a constructor can only return its own type. No subtypes, no other classes, no reused instances, no null—only a new instance of that type. So you're looking for a solution that operates outside the confines of a constructor here. The simplest and most common workaround is to write a static factory method (usually named newInstance or getInstance) which returns any new or existing instance of the enclosing class and can return a subclass or null without trouble.
Your points about your solution 1 and 2 are valid. It'd be great to avoid making the data types aware of the UI, and in your situation (with only four types) I'd probably opt for your solution 2. If you have operations that will vary among those types—which is a pretty common requirement in a GUI that puts a mixture of types into a tree—Bittenus's solution is probably worth it. (It's a lot of code to handle if you only need to do this sort of thing once.)
If you somehow expect your type count to grow but your operations to never grow, one alternative is to extract the polymorphic creation into a separate Factory, which might look like this:
class MyAppTreeNode {
interface Factory {
MyAppTreeNode create(DataType type);
}
}
class AlphaTreeNode extends MyAppTreeNode {
static class Factory implements MyAppTreeNode.Factory {
#Override public AlphaTreeNode create(DataType type) {
// Remember, in an override your return types can be more-specific
// but your parameter types can only be less-specific
return new AlphaTreeNode((DataTypeAlpha) type);
}
}
}
Then you can just make a map (though consider Guava's ImmutableMap for better semantics):
private static Map<Class<?>, MyAppTreeNode.Factory> factoryMap = new HashMap<>();
static {
factoryMap.put(DataTypeAlpha.class, new AlphaTreeNode.Factory());
// ...
}
public static createTreeNode(DataType type) {
return factoryMap.get(type.getClass()).create(type);
}
More trouble than it's worth? Probably, in most cases. But bear in mind that it's probably the best that Guice can get you, as well. Guice has some ability to auto-generate the Factory implementation for you, but you'll still need to map DataType to MyAppTreeNode.Factory one way or another, and it's going to have to live in a Map, a conditional, or the double indirection that powers the Visitor pattern.
Hope this helps, if only to endorse the answers you already have!

Understanding best use of Java Generics in this example case

Let's say I have a manufacturing scheduling system, which is made up of four parts:
There are factories that can manufacture a certain type of product and know if they are busy:
interface Factory<ProductType> {
void buildProduct(ProductType product);
boolean isBusy();
}
There is a set of different products, which (among other things) know in which factory they are built:
interface Product<ActualProductType extends Product<ActualProductType>> {
Factory<ActualProductType> getFactory();
}
Then there is an ordering system that can generate requests for products to be built:
interface OrderSystem {
Product<?> getNextProduct();
}
Finally, there's a dispatcher that grabs the orders and maintains a work-queue for each factory:
class Dispatcher {
Map<Factory<?>, Queue<Product<?>>> workQueues
= new HashMap<Factory<?>, Queue<Product<?>>>();
public void addNextOrder(OrderSystem orderSystem) {
Product<?> nextProduct = orderSystem.getNextProduct();
workQueues.get(nextProduct.getFactory()).add(nextProduct);
}
public void assignWork() {
for (Factory<?> factory: workQueues.keySet())
if (!factory.isBusy())
factory.buildProduct(workQueues.get(factory).poll());
}
}
Disclaimer: This code is merely an example and has several bugs (check if factory exists as a key in workQueues missing, ...) and is highly non-optimal (could iterate over entryset instead of keyset, ...)
Now the question:
The last line in the Dispatcher (factory.buildProduct(workqueues.get(factory).poll());) throws this compile-error:
The method buildProduct(capture#5-of ?) in the type Factory<capture#5-of ?> is not applicable for the arguments (Product<capture#7-of ?>)
I've been racking my brain over how to fix this in a type-safe way, but my Generics-skills have failed me here...
Changing it to the following, for example, doesn't help either:
public void assignWork() {
for (Factory<?> factory: workQueues.keySet())
if (!factory.isBusy()) {
Product<?> product = workQueues.get(factory).poll();
product.getFactory().buildProduct(product);
}
}
Even though in this case it should be clear that this is ok...
I guess I could add a "buildMe()" function to every Product that calls factory.buildProduct(this), but I have a hard time believing that this should be my most elegant solution.
Any ideas?
EDIT:
A quick example for an implementation of Product and Factory:
class Widget implements Product<Widget> {
public String color;
#Override
public Factory<Widget> getFactory() {
return WidgetFactory.INSTANCE;
}
}
class WidgetFactory implements Factory<Widget> {
static final INSTANCE = new WidgetFactory();
#Override
public void buildProduct(Widget product) {
// Build the widget of the given color (product.color)
}
#Override
public boolean isBusy() {
return false; // It's really quick to make this widget
}
}
Your code is weird.
Your problem is that you are passing A Product<?> to a method which expects a ProductType which is actually T.
Also I have no idea what Product is as you don't mention its definition in the OP.
You need to pass a Product<?> to work. I don't know where you will get it as I can not understand what you are trying to do with your code
Map<Factory<?>, Queue<Product<?>>> workQueues = new HashMap<Factory<?>, Queue<Product<?>>>();
// factory has the type "Factory of ?"
for (Factory<?> factory: workqueues.keySet())
// the queue is of type "Queue of Product of ?"
Queue<Product<?>> q = workqueues.get(factory);
// thus you put a "Product of ?" into a method that expects a "?"
// the compiler can't do anything with that.
factory.buildProduct(q.poll());
}
Got it! Thanks to meriton who answered this version of the question:
How to replace run-time instanceof check with compile-time generics validation
I need to baby-step the compiler through the product.getFactory().buildProduct(product)-part by doing this in a separate generic function. Here are the changes that I needed to make to the code to get it to work (what a mess):
Be more specific about the OrderSystem:
interface OrderSystem {
<ProductType extends Product<ProductType>> ProductType getNextProduct();
}
Define my own, more strongly typed queue to hold the products:
#SuppressWarnings("serial")
class MyQueue<T extends Product<T>> extends LinkedList<T> {};
And finally, changing the Dispatcher to this beast:
class Dispatcher {
Map<Factory<?>, MyQueue<?>> workQueues = new HashMap<Factory<?>, MyQueue<?>>();
#SuppressWarnings("unchecked")
public <ProductType extends Product<ProductType>> void addNextOrder(OrderSystem orderSystem) {
ProductType nextProduct = orderSystem.getNextProduct();
MyQueue<ProductType> myQueue = (MyQueue<ProductType>) workQueues.get(nextProduct.getFactory());
myQueue.add(nextProduct);
}
public void assignWork() {
for (Factory<?> factory: workQueues.keySet())
if (!factory.isBusy())
buildProduct(workQueues.get(factory).poll());
}
public <ProductType extends Product<ProductType>> void buildProduct(ProductType product) {
product.getFactory().buildProduct(product);
}
}
Notice all the generic functions, especially the last one. Also notice, that I can NOT inline this function back into my for loop as I did in the original question.
Also note, that the #SuppressWarnings("unchecked") annotation on the addNextOrder() function is needed for the typecast of the queue, not some Product object. Since I only call "add" on this queue, which, after compilation and type-erasure, stores all elements simply as objects, this should not result in any run-time casting exceptions, ever. (Please do correct me if this is wrong!)

Design pattern to handle settings in subclasses?

I have a small hierarchy of classes that all implement a common interface.
Each of the concrete class needs to receive a settings structure containing for instance only public fields. The problem is that the setting structure
has a part common to all classes
has another part that vary from one concrete class to another
I was wondering if you had in your mind any elegant design to handle this. I would like to build something like:
BaseFunc doer = new ConcreteImplementation1();
with ConcreteImplementation1 implements BaseFunc. And have something like
doer.setSettings(settings)
but have the ''settings'' object having a concrete implementation that would be suitable to ConcreteImplementation1.
How would you do that?
This may be a named design pattern, if it is, I don't know the name.
Declare an abstract class that implements the desired interface. The abstract class constructor should take an instance of your settings object from which it will extract the global settings. Derive one or more classes from the abstract class. The derived class constructor should take an instance of your settings object, pass it to the parent class constructor, then extract any local settings.
Below is an example:
class AbstractThing implements DesiredInterface
{
private String globalSettingValue1;
private String globalSettingValue2;
protected AbstractThing(Settings settings)
{
globalSettingValue1 = settings.getGlobalSettingsValue1();
globalSettingValue2 = settings.getGlobalSettingsValue2();
}
protected String getGlobalSettingValue1()
{
return globalSettingValue1;
}
protected String getGlobalSettingValue2()
{
return globalSettingValue2;
}
}
class DerivedThing extends AbstractThing
{
private String derivedThingSettingValue1;
private String derivedThingSettingValue2;
public DerivedThing(Settings settings)
{
super(settings);
derivedThingSettingValue1 = settings.getDerivedThingSettingsValue1();
derivedThingSettingValue2 = settings.getDerivedThingSettingsValue2();
}
}
Have a matching hierarchy of settings objects, use Factory to create the settings that match a specific class.
Sounds like you need a pretty standard Visitor pattern.
To put it simple, suppose, that all your properties are stored as key-value pairs in maps. And you have 3 classes in your hierarchy: A, B, C. They all implement some common interface CI.
Then you need to create a property holder like this:
public class PropertyHolder {
public Map<String, String> getCommonProperties () { ... }
public Map<String, String> getSpecialPropertiesFor (CI a) { return EMPTY_MAP; }
public Map<String, String> getSpecialPropertiesFor (A a) { ... }
public Map<String, String> getSpecialPropertiesFor (B b) { ... }
...
}
All your classes should implement 1 method getSpecialProperties which is declared in the interface CI. The implementation as simple as:
public Map<String, String> getSpecialProperties (PropertyHolder holder) {
return holder.getSpecialPropertiesFor (this);
}
I went down this route once. It worked, but after decided it wasn't worth it.
You can define a base class MyBean or something, and it has its own mergeSettings method. Every class you want to use this framework can extend MyBean, and provide its own implementation for mergeSettings which calls the superclasses mergeSettings. That way the common fields can be on the super class. If you want to get really fancy you can define and interface and abstract class to really make it pretty. And while your at it, maybe you could use reflection. anyway, mergeSettings would take a Map where the key is the property name. Each class would have its constants to related to the keys.
class MyBean extends AbstractMyBean ... {
public static final String FIELD1 = 'field1'
private String field1
public mergeSettings(Map<String, Object> incoming) {
this.field1 = incoming.get(FIELD1);
// and so on, also do validation here....maybe put it on the abstract class
}
}
Its a lot of work for setters though...
I started toying with a new pattern that I called "type-safe object map". It's like a Java Map but the values have type. That allows you to define the keys that each class wants to read and get the values in a type safe way (with no run-time cost!)
See my blog for details.
The nice thing about this is that it's still a map, so you can easily implement inheritance, notification, etc.
You could use Generics to define what kind of settings this instance need. Something like this:
public abstract class MySuperClass<T extends MySettingsGenericType>{
public MySuperClass(T settings){
//get your generic params here
}
}
public class MyEspecificClass extends MySuperClass<T extends MySettingsForThisType>{
public MySuperClass(T settings){
super(settings);
//Get your espefic params here.
}
}
//and you could use this
BaseFunc doer = new ConcreteImplementation1(ConcreteSettingsFor1);
//I dont compile this code and write in a rush. Sorry if have some error...

Categories

Resources