So lets assume I am having the following stuff defined:
public interface IExportTool {
void export(IReport iReport);
}
And then attempting to use it:
public class KibanaExporter implements IExportTool{
public void export(IReport kibana) {
kibana = (Kibana) kibana;
((Kibana) kibana).toJSON();
}
}
But there are also other classes which would again be doing something like that too:
public class MetricExporter implements IExportTool{
public void export(IReport metric) {
metric = (Metric) metric;
((Metric) metric).toJSON(); // might be something else here like toXML etc
}
}
Please note that both Kibana and Metric are implementing IReport<KibanaRow> and IReport<MetricRow> respectively, while the IReport interface looks like:
public interface IReport<T> {
void addRow(T row);
}
I don't like all this casting, this doesn't feel right nor gives me autocomplete, so any suggestion how to do it properly?
From what you've posted, it's clear that both Kibana and Metric are subtypes of IReport.
In that case, you can make the interface generic:
interface IExportTool<R extends IReport> {
void export(R iReport);
}
And then change the implementations in this fashion:
public class KibanaExporter implements IExportTool<Kibana>{
public void export(Kibana kibana) {
kibana.toJSON();
}
}
And:
public class MetricExporter implements IExportTool<Metric> {
public void export(Metric metric) {
metric.toJSON();
}
}
This version allows the compiler to understand and validate that only instances of subtypes of IReport will ever be passed to export(). Code using this will be validated by the compiler, such that MetricExporter().export() can only be called with an object of type Metric and KibanaExporter().export() with an object of type Kibana.
And with that, type casts are no longer needed.
Related
While trying to program to interfaces, I regularly find myself in the following situation:
I have several very similar classes representing containers or algorithms for different types.
I would like to define a common interface for these classes.
Consider, e.g., a string container.
Such a container will likely have string processing methods.
Since those methods are easily represented using generic interfaces, I am ignoring them.
Here, I want to focus on methods that can be used to process or provide references to other string containers:
public class StringContainer {
StringContainer produce() {
return new StringContainer();
}
void consume(StringContainer stringContainer) {
}
}
This class can be used just fine in code like:
public class Main {
public static void main(String[] args) {
StringContainer stringContainer = new StringContainer();
stringContainer.produce();
stringContainer.consume(stringContainer);
}
}
The problem is: I'm using a concrete class and not an interface to refer to the string container.
What if I want to introduce a double container or a list container later and want to leave the rest of the code as is?
Maybe generics could form a solution to this problem?
Here is my try.
I first define a generic container class:
interface Container<T> {
Container<T> produce();
void consume(Container<T> container);
}
I then create type-specific implementations of the form:
public class StringContainer implements Container<String> {
#Override
public Container<String> produce() {
return new StringContainer();
}
#Override
public void consume(Container<String> container) {
}
public void consume(StringContainer container) {
}
}
The above classes can be used as follows:
public class Main {
public static void main(String[] args) {
Container<String> stringContainer = new StringContainer();
stringContainer.produce();
stringContainer.consume(stringContainer);
}
}
However, the above approach has several drawbacks:
The consume(Container<String> container) method accepts other types than StringContainer.
In consume(Container<String> container), the parametrized type Container<String> has to be used when processing container. I can't assign it to StringContainer variables (without type checks or casts).
The alternative consume(StringContainer container) method is defined for StringContainer objects, but can't be called from a Container<String> reference.
Finally, to me, the line Container<String> stringContainer = new StringContainer(); has an awkward-looking notation that suggests a diamond operator is missing in new StringContainer().
What is the idiomatic way to define a general interface for several type-specific classes, which doesn't have (all) the above drawbacks?
Should I ignore point 4 and address points 1 and 2 by adding type checks/casts, throwing an UnsupportedOperationException or IllegalArgumentException in case passed objects aren't StringContainers?
Or is there another way to use generics? Can type bounds help me, for example?
Or should I look for a solution outside of generics?
Update:
Based on the answers given so far, I have come to realize that I had conflicting goals:
On the one hand, I wanted to restrict the types accepted by container methods (as described by points 1 and 2).
On the other hand, I wanted to address and pass container types using an interface reference (as hinted at by point 3 and my implicit desire to keep the second main method as is).
I now see that these goals cannot both be reached statically.
Since I don't want to rephrase my question in retrospect, I'll forget about my second (rather implicit) goal and mark the first-posted solution that addressed points 1 and 2 as the answer.
Is this what you're looking for? It's called a recursive type bound.
interface Container<T extends Container<T>> {
T produce();
void consume(T container);
}
class StringContainer implements Container<StringContainer> {
#Override
public StringContainer produce() {
return new StringContainer();
}
#Override
public void consume(StringContainer container) {
}
}
It seems that you have two APIs, and you should treat them separately with separate interfaces. Yes, you can merge them into the same interface with distinct method names.
I think you should have two interfaces for your "containers" and for your "containers of containers". Here's what I'd make it:
interface Container<T> {
T produce();
void consume(T container);
}
interface MetaContainer<T, R extends Container<T>> {
R produceContainer();
void consumeContainer(R container);
}
class StringContainer implements Container<String>, MetaContainer<String, StringContainer> {
#Override
public String produce() {
return "";
}
#Override
public void consume(String container) {
}
#Override
public StringContainer produceContainer() {
return this;
}
#Override
public void consumeContainer(StringContainer container) {
}
}
I implemented both interfaces using the same class to emulate your StringContainer class.
Disclaimer: Bear with me for a good amount of code to explain the scenario.
In one of the maven modules (core), we have the following classes:
abstract class ReportingEvent {
}
abstract class Element {
public <E extends ReportingEvent> Optional<E> getReportEvent() {
return Optional.empty();
}
}
services such as:
public interface Reporting<E extends ReportingEvent> {
void report(E event);
}
interface InternalService {
}
public class InternalServiceImpl implements InternalService {
#Inject
Reporting<ReportingEvent> reporting; // 1. Possible to use a generic type? How?
private void reportEvents(BatchRequest batchRequest) {
batchRequest.stream()
// section below is of importance
.map(m -> m.getEntity().getReportEvent()) // the generic method from 'Element'
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(event -> reporting.report(event)); // method from 'Reporting'
}
}
class CoreBindingModule extends AbstractModule {
protected void configure() {
bind(InternalService.class).to(InternalServiceImpl.class).in(Singleton.class);
}
}
Further in another maven module(consumer) that we deploy, we have classes related to and implementing the above as:
abstract class BaseReporting extends ReportingEvent {
}
class ColdReporting extends BaseReporting {
}
abstract class Node extends Element {
}
class Cold extends Node {
#Override
public Optional<ColdReporting> getReportEvent() {
return Optional.ofNullable(new ColdReporting()); // some business logic
}
}
class ReportingImpl implements Reporting<ReportingEvent> { // 2. Use 'BaseReporting' here
void report(ReportingEvent event){}
}
class ConsumerBindingModule extends AbstractModule {
protected void configure() {
bind(new TypeLiteral<Reporting<ReportingEvent>>() {}).to(ReportingImpl.class).in(Singleton.class);
}
}
The above code works fine. But the problem is the use of types that don't quite relate to the modules.
A... So if I change the binding in the consumer module to
bind(new TypeLiteral<Reporting<BaseReporting>>() {}).to(ReportingImpl.class).in(Singleton.class);
with
class ReportingImpl implements Reporting<BaseReporting> {
void report(BaseReporting event){}
}
I get an error
No implementation for Reporting<ReportEvent> was bound.
while locating Reporting<ReportEvent> for field at InternalServiceImpl.reporting(InternalServiceImpl.java:21)
which is relevant and I cannot make use of Reporting<BaseReporting> in the core module anyway.
B... On the other hand if I try to inject Reporting as:
#Inject
Reporting<? extends ReportingEvent> reporting;
then IDEA states
Required type: capture of ?
Provided: ReportingEvent
on the line
...forEach(event -> reporting.report(event))
Is there a way to get around this situation while trying to solve for 1 and 2 as mentioned in the code sections?
(I might be restating what you already know for the most part)
Keeping aside your Guice related modules and configuration, your problem can be written down as
Reporting<ReportingEvent> reportingEvent = new ReportingImpl();
Reporting<? extends ReportingEvent> reporting = baseReporting;
reporting.report(reportingEvent); //won't work
which is identical to
List<? extends String> list = new ArrayList<>();
list.add("a"); //won't work
Say, you have a HotReporting class that extends BaseReporting, thus you have something like this
public class ReportingImpl implements Reporting<ReportingEvent> {
public void report(ReportingEvent event){}
}
public class ColdReportingImpl implements Reporting<ColdReporting> {
public void report(ColdReporting event){}
}
public class HotReportingImpl implements Reporting<HotReporting> {
public void report(HotReporting event){}
}
Assume if you injected a HotReportingImpl for the field Reporting<? extends ReportingEvent> reporting.
In your code what if m.getEntity().getReportEvent() returns a ColdReporting? It is not compatible with what the report method expects here (a HotReporting).
Option 1:
I would try to get rid of the generic type parameters and define Reporting as
public interface Reporting {
void report(ReportingEvent event);
}
public class BaseReportingImpl implements Reporting {
#Override
public void report(ReportingEvent event) {
}
}
//... and so on
Problems:
If you relied on the exact subtype of a ReportingEvent in the implementation (need typecasts which is not good).
Still, a HotReportingImpl can get a ColdReporting object as an argument.
Option 2:
You can make the InternalService generic by adding the type parameters to it.
If the classes implementing Reporting have to deal with concrete types of ReportingEvent, then it doesn't seem right for Element to return the base type (ReportingEvent).
Have a look at Typesafe heterogeneous containers by Joshua Bloch. Your problem overlaps with that. You can maintain a mapping from the type of ReportingEvent to the corresponding subclass of Reporting with that type argument.
import java.util.*;
import java.lang.*;
import java.io.*;
class mainA {
private mainA obj;
public mainA(int type) {
System.out.println("accessing mainA");
switch(type) {
case 1:
obj = new mysql();
break;
case 2:
obj = new mssql();
break;
default:
break;
}
}
}
class mysql extends mainA {
public void printme() {
System.out.println("accessing mysql");
}
}
class mssql extends mainA {
public void printme() {
System.out.println("accessing mssql");
}
}
class C2 extends mainA {
public C2() {
super();
}
public static void main(String args[]){
Object b = new C2();
b.printme();
}
}
I need to achieve the following scenario. It would be great if someone can help me out.
I'm trying to create a common API library set which can be scaled to as many backend databases as possible.
The idea is to create an object of C2, which in turn would return the value of either mysql/mssql based on the dbtype. The type parameter can be obtained from any where in the code. mainA is the super class which consists of config params. Type can be obtained here as well. The problem here is that I'm stuck with not being able to get the object of mysql/mssql from C2. The ideal situation would be to create an object of C2 which refers to mainA that gets the type and inits either mssql/mysql. C2.printme must call the db class which was specified in the type.
Would generic classes be of any help here?
you can have an instanceof test to cast the object but it is lame as you would have to change your code if you are adding a new type of DB object.
You can have a good interface and make the subclasses implement it so that you can call through your interface without caring about the actual implementation object.
Coding to Interface is what you should be doing.
You've got some work ahead of you. You'll want to read up on interfaces. In your example, you can do something like the following (it's a bit silly in the real world).
Let's call our interface Printable.java (by convention, starts with either the capital letter "I" or ends in "-ible", "able," etc). I wouldn't really call it Printable, but for the purpose of this example:
public interface Printable {
public void logDatabaseType();
}
Your parent class (we can make it abstract so that it cannot be created directly without an underlying implementation):
public abstract class Database implements Printable {
#Override
public void logDatabaseType() {
System.out.println("logDatabaseType()");
}
}
Your subclasses:
public class MySQL extends Database implements Printable {
#Override
public void logDatabaseType() {
System.out.println("Accessing MySQL");
}
}
public class MicrosoftSQL extends Database implements Printable {
#Override
public void logDatabaseType() {
System.out.println("Accessing MSSQL");
}
}
In your test class (you should try to get your feet wet with JUnit as early as possible):
public class DatabaseLogTest {
#Test
public void printDatabaseType() {
//programming by interface
Printable printable = new MySql();
printable.logDatabaseType();
printable = new MicrosoftSQL();
printable.logDatabaseType();
//then later you can do
//someMethod(printable);
//and the printable object will retain whatever was instantiated
//and someMethod will be blissfully ignorant of the actual implementation
}
}
#Override is important because it tells your IDE and the developer that you're overriding an implementation and the IDE will spit out errors if the implied contract is not met. You should have this whenever you're overriding.
You'd also want to use a logger (e.g., SLF4j over Log4J or logback) rather than System.out.println() method calls.
I have a Java generics question I was hoping someone could answer. Consider the following code:
public interface Event{}
public class AddressChanged implements Event{}
public class AddressDiscarded implements Event{}
public interface Handles<T extends Event>{
public void handle(T event);
}
I want to implement this Handles interface like this:
public class AddressHandler implements Handles<AddressChanged>, Handles<AddressDiscarded>{
public void handle(AddressChanged e){}
public void handle(AddressDiscarded e){}
}
But java doesn't allow implementing Handles twice using the Generic. I was able to accomplish this with C#, but cannot figure a workaround in java without using Reflection or instanceof and casting.
Is there a way in java to implement the Handles interface using both generic interfaces? Or perhaps another way to write the Handles interface so the end result can be accomplished?
Going after #Amir Raminfar, you can use visitor pattern
interface Event{
void accept(Visitor v);
}
interface Visitor {
void visitAddressChanged(AddressChanged a);
void visitAddressDiscarded(AddressDiscarded a);
}
class AddressChanged implements Event{
#Override
public void accept(Visitor v) {
v.visitAddressChanged(this);
}
}
class AddressDiscarded implements Event{
#Override
public void accept(Visitor v) {
v.visitAddressDiscarded(this);
}
}
class AddressHandler implements Visitor {
void handle(Event e){
e.accept(this);
}
public void visitAddressChanged(AddressChanged e){}
public void visitAddressDiscarded(AddressDiscarded e){}
}
You can't do that in Java. You can only implement one concrete realization of the same generic interface. I would do this instead:
public class AddressHandler implements Handles<Event>{
public void handle(Event e){
if(e instanceof AddressDiscarded){
handleDiscarded(e);
} else if(e instanceof AddressChanged){
handleChanged(e);
}
}
public void handleDiscarded(AddressDiscarded e){}
public void handleChanged(AddressChanged e){}
}
No, because different "concrete" generic types in Java compile to the same type. The actual interface your object will implement is:
public interface Handles {
public void handle(Event event);
}
And, obviously, you can't have two different methods with an identical signature...
AFAIK you cannot do that, because when compiling the source code in Java these will both boil down to handle(Event), making the method ambiguous.
The generic information is not available during runtime in Java, in contrast to C#. That is why there it works as you describe.
You will have to change the method names to make them unique, like handleAddressChanged and handleAddressDiscarded.
This is indeed one of the weak points of Java generics.
Unfortunately not. The usual solution (fat, ugly, fast) is to create one Handles interface (i.e. HandlesAddressChange, HandlesAddressDiscarded) and give each of them a different method (handleAddressChange(...), handleAddressDiscarded()).
That way, the Java runtime can tell them apart.
Or you can use anonymous classes.
It isn't allowed because Java erases generic signatures during compilation. The interface method will actually have the signature
public void handle(Object event);
So you have two choices. Either implement separate Handlers for different events:
public class AddressChangedHandler implements Handles<AddressChanged>{ /* ... */ }
public class AddressDiscardedHandler implements Handles<AddressDiscarded>{ /* ... */ }
or implement one handler for all but check the type of the incoming event:
public void handle(Event e){
if (e instanceof AddressChanged) {
handleAdressChanged(e);
}
else if (e instanceof AddressDiscareded) {
handleAdressDiscarded(e);
}
}
An implementation like this won't work due to the constraints of the java specification.
But if you're not afraid to use AOP or some sort of an IOC-Container you could use annotations for that. Than your Aspects or the container could manage the messaging infrastructure and call the methods you annotate.
First you have to create the annotations.
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface EventConsumer {}
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface Handles{}
The you may annotate your class like that:
#EventConsumer
public class AddressHandler{
#Handles
public void handle(AddressChanged e){}
#Handles
public void handle(AddressDiscarded e){}
}
If you don't mind using a (small) library, here's one I wrote that solves your problem:
https://github.com/bertilmuth/requirementsascode
You'd build a model like this
Model.builder()
.on(AddressChanged.class).system(this::handleAddressChanged)
.on(AddressDiscarded.class).system(this::handleAddressDiscarded)
.build()
and run it.
How to do that exactly is described on the website.
Given the following Class and Service layer signatures:
public class PersonActionRequest {
PersonVO person
// ... other fields
}
public class MyServiceLayerClass {
public void requestAction(PersonActionRequest request)
{
PersonVO abstractPerson = request.getPerson();
// call appropriate executeAction method based on subclass of PersonVO
}
private void executeAction(PersonVO person) {}
private void executeAction(EmployeeVO employee) {}
private void executeAction(ManagerVO manager) {}
private void executeAction(UnicornWranglerVO unicornWrangler) {}
}
As discussed here, java will select the best method based on type info at compile time. (Ie., it will always select executeAction(PersonVO person) ).
What's the most appropriate way to select the correct method?
The internet tells me that using instanceof gets me slapped. However, I don't see the appropraite way to select the method without explictly casting abstractPerson to one of the other concrete types.
EDIT: To Clarify - The VO passed in is a simple ValueObject exposed for web clients to instantiate and pass in. By convention it doesn't have methods on it, it's simply a data structure with fields.
For this reason, calling personVO.executeAction() is not an option.
Thanks
Marty
If executeAction was a method in a base class or interface that was common to PersonVO, EmployeeVO, ManagerVO and UnicornWranglerVO, you could just call abstractPerson.executeAction() instead of having multiple overridden methods.
Your principle obstacle to polymorphism here seems to be a 'dumb-struct' data object + 'manager class' service non-pattern. The "more polymorphic' approach would be for execute() to be a method that the various person implementations override.
Assuming that can't change, the way you do multiple dispatch in Java is with visitor-looking callbacks.
public interface PersonVisitor {
void executeAction(EmployeeVO employee);
void executeAction(ManagerVO manager);
void executeAction(UnicornWranglerVO unicornWrangler);
}
public abstract class PersonVO {
public abstract void accept(PersonVisitor visitor);
}
public class EmployeeVO extends PersonVO {
#Override
public void accept(PersonVisitor visitor) {
visitor.executeAction(this);
}
}
public class MyServiceLayerClass implements PersonVisitor {
public void requestAction(PersonActionRequest request)
{
PersonVO abstractPerson = request.getPerson();
abstractPerson.accept(this);
}
public void executeAction(EmployeeVO employee) {}
public void executeAction(ManagerVO manager) {}
public void executeAction(UnicornWranglerVO unicornWrangler) {}
}
You could change the way you are approaching the design and use a Visitor, passing the executor into the Person and have the person type determine which to call.
The Visitor pattern is often used to overcome Java lacking double-dispatch.
I would explicitly cast the abstractPerson. Not only does it ensure the JVM gets the right method, it makes it a hell of a lot easier to read and ensure you know what's going on.