I have an enum and want to have a generic function that could accept any class that implements a maker interface.
public interface IComponentDataExporter { // Marker Interface }
public class ComponentsDataExporter implements IComponentDataExporter {
public ComponentTeaser populateFeatured(ComponentTeaserConfiguration componentConfig) { return null; }
}
public class BusinessComponentsDataExporter implements IComponentDataExporter { // methods }
public enum ComponentTypeEnum {
FEATURED(ComponentsDataExporter::populateFeatured);
public final BiFunction<? super IComponentDataExporter, ComponentTeaserConfiguration, ComponentTeaser> exporter;
private ComponentTypeEnum( BiFunction<? super IComponentDataExporter, ComponentTeaserConfiguration, ComponentTeaser> exporter) {
this.exporter = exporter;
}
}
I am getting this compilation error The type ComponentsDataExporter does not define populateFeatured(IComponentDataExporter, ComponentTeaserConfiguration) that is applicable here
My main issue is BIFunction
I want it to accepts either ComponentsDataExporter
or BusinessComponentsDataExporter
that's why I tried to use a generic wildcard (? extends IComponentDataExporter
and? super IComponentDataExporter
). It is working fine if I replace wildcard with a specific class.
Sorry for not being clear in my questation so I will try to explain more and little of history.
I want to force whoever adding a new enum value to provide a method which is exporting data for that component. Logic of export method cannot be placed in Enum as it requires access to spring managed beans and may have a lot of business logic.
I already did that and it was working perefectly, you can have a look on this demo .
My problem started when I noticed that having all of export methods in one class will be too much so I decided to have different kind of implementation ( BusinessComponentsDataExporter
and ComponentsDataExporter
) each one of them handles set of components.
To do that separation I have added a marker interface so I can mark any exporter class and updated BiFunction in Enum to have wildcard so it can accept any kind of object that implements my marker interface.
BiFunction<? super IComponentDataExporter, ComponentTeaserConfiguration, ComponentTeaser> exporter
The solutions I am working on right now is reverting to my old version of BiFunction which was like the demo
BiFunction<ComponentsDataExporter, ComponentTeaserConfiguration, ComponentTeaser>
Considering ComponentsDataExporter
as facade which have instances of different kind of exporters where the whole exporting logic resides ( businessExporter
, contentExporter
etc) so facade will have all high levels methods that can be called from Enum. Here's example for the solution I am considering right now
Read carefully what your error message says…
„...
ComponentsDataExporter does not define populateFeatured(IComponentDataExporter, ComponentTeaserConfiguration)
...“
BiFunction<T,U,R>
is defined to take two input arguments . But you define populateFeatured(ComponentTeaserConfiguration)
with only one parameter…
...
public ComponentTeaser populateFeatured(ComponentTeaserConfiguration componentConfig)...
...
So you
need to
could rewrite it like I do here …
...
public static ComponentTeaser populateFeatured( IComponentDataExporter self, ComponentTeaserConfiguration componentConfig )...
...
Notice it's static
in my demo . If you want to use a method reference ( FEATURED(ComponentsDataExporter::populateFeatured)
) then the method either has to be static
or you need an object instance to call it if it's not static
( new ComponentsDataExporter()::populateFeatured
).
And then the BiFunction
changes to…
...
BiFunction< IComponentDataExporter, ComponentTeaserConfiguration, ComponentTeaser >...
...
An upper bound wildcard ( ? extends IComponentDataExporter
) as the first type argument to your BiFunction
wouldn't compile. A lower bound wildcard ( ? super IComponentDataExporter
) would actually work there. But it would be confusing. It's better off being specified as simply a normal interface type argument ( IComponentDataExporter
).
That would then be used like…
ComponentTeaserConfiguration conf = null;
BusinessComponentsDataExporter exp = null;
ComponentTypeEnum featured = ComponentTypeEnum.FEATURED;
ComponentTeaser teaser = featured.export( exp, conf );
teaser.tease( );
Click the green Start button at the top of the demo to see it run.
EDIT : If I understand your follow-up comments correctly, I don't think you want a BiFunction
at all.
From what I gather from your comments — and your original implementation of populateFeatured(...)
— if seems like what you actually want is a Function
…
...
Function< ComponentTeaserConfiguration, ComponentTeaser >...
...
Because your questions and comments are not crystal clear, these suggestions are based on what I assume your intention is.
„ …the call will be something like this
ComponentTypeEnum.Featured.exporter.apply(exporterInstance, configObj)
… “
One of the things that you have not made crystal clear is the reason why you need to pass a IComponentDataExporter
into populateFeatured(...)
, given that ComponentsDataExporter
is itself a concrete implementation of IComponentDataExporter
. Please update your question with something that clarifies that?
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.