How to use method with generics and inheritance? - java

Having the following classes:
public interface Step<C extends Config> {
void setConfig(C config);
}
and
public class ValidationStep implements Step<ValidationConf> {
public void setConfig(ValidationConf conf) {}
// implementation
}
and
public class ProcessStep implements Step<ProcessConf> {
public void setConfig(ProcessConf conf) {}
// implementation
}
and
public interface Config {
Class<? extends Step> type();
}
and
public class ValidationConf implements Config {
public Class<? extends Step> type() {
return ValidationStep.class;
}
}
and
public class ProcessConf implements Config {
public Class<? extends Step> type() {
return ProcessStep.class;
}
}
so, the application needs to dynamically instantiate Step subclasses objects, set the configuration accordingly and run the step, like this.
List<Config> configs = loadConfigsFromRepository(); // contain all subtypes of Config
for (Config conf: configs) {
Step<? extends Config> step = conf.type().getDeclaredConstructor().newInstance();
step.setConfig(conf); // compiler complains
}
Error message:
"The method setConfig(capture#8-of ? extends Config) in the type
Step<capture#8-of ? extends Config> is not applicable for the
arguments (Config)".
Checking the documentation, looks like Java won´t be friendly in this case:
https://docs.oracle.com/javase/tutorial/java/generics/wildcardGuidelines.html
What are the possible solutions to overcome this code restriction step.setConfig(conf);?
EDITED [SOLUTION]
Code can be viewed here: https://github.com/danieldestro/cucumber-salad/tree/generics/src/main/java/my/generics

Because Step.setConfig( Config ) is a „consumer“, one way to resolve the „is not applicable for the arguments (Config)“ error you get is to use a lower bound like I demonstrate here…
…
List< ? extends Config > configs = loadConfigsFromRepository( ); // contain all subtypes of Config
for ( Config conf: configs ) {
Step< ? super Config > step = conf.type( ).getDeclaredConstructor( ).newInstance( );
step.setConfig( conf ); // *set* makes Step a „consumer“
}
…
That way you don't need the cast that the other answer proposes.
My loadConfigsFromRepository( ) is implemented like…
static List< ? extends Config > loadConfigsFromRepository(){
return of( new ValidationConf( ), new ProcessConf( ) );
}

Get rid of the wildcard. You don't need it.
Step<Config> step = (Step<Config>) conf.type().getDeclaredConstructor().newInstance();

Your approach is not fully correct. I reccomend you not to use Reflections until you really need it.
Pay attention, that all these implementation should be hidden inside the package and only Step interface should be public. Config implementation holds all data to create Step class, so just delegate it to this.
package steps
public interface Step<C extends Config> {
void run(Context context);
}
private final class ValidationStep implements Step<ValidationConf> {
private final ValidationConf config;
public ValidationStep(ValidationConf config) {
this.config = config;
}
}
private class ProcessStep implements Step<ProcessConf> {
private final ProcessConf config;
public ValidationStep(ProcessConf config) {
this.config = config;
}
}
public interface Config {
Step<? extends Config> createStep();
}
private class ValidationConf implements Config {
public Step<ValidationConf> createStep() {
return new ValidationStep(this);
}
}
private class ProcessConf implements Config {
public Step<ValidationConf> createStep() {
return new ProcessConf(this);
}
}
package foo
List<Config> configs = loadConfigsFromRepository();
for (Config config : loadConfigsFromRepository()) {
config.createStep().run(context);
}

Related

How to inject bean of type Supplier?

I have code as follows
public class A {
#Inject
private Supplier<Set<String>> set;
.
.
}
I am writing test cases for this class, where my Unit test looks like :
#Test(groups = "MyApp.unit")
public class ATest extends someOtherClass {
#Inject
private A a;
& my unit config looks like
#Configuration
#Import({someClass.class})
public class UnitTestConfig {
...
#Bean
public Supplier<Set<String>> set() {
Supplier<Set<String>> items = () -> Sets.newHashSet("100");
return items;
}
#Bean
public A a() {
return new A();
}
}
I am unable to inject Supplier bean into my class A. Had put debug points and tried testing, it enters the bean function but Supplier class doesnt get created. It gives the message "Class has no fields"
All other beans seem fine. Does anyone have any insights on this?
If you're already using the #Configuration to configure the bean, why won't you use constructor injection?
I suggest you to rewrite the A class as follows:
public class A {
private final Supplier<Set<String>> sup;
public A(Supplier<Set<String>> sup) {
this.sup = sup;
}
}
Now you can use one of the following options:
#Configuration
public class SampleConfig {
#Bean
public Supplier<Set<String>> set () {
return () -> Set.of("a","b", "c");
}
#Bean
public A a (Supplier<Set<String>> sup) {
return new A(sup);
}
}
Or another way:
#Configuration
public class SampleConfig {
#Bean
public Supplier<Set<String>> set () {
return () -> Set.of("a","b", "c");
}
#Bean
public A a () {
return new A(set());
}
}
In the second option I call set() as if its a regular method. Spring handles classes annotated with #Configuration, so its a "special" call used for injection.
Since a supplier is a singleton, multiple calls to this set method (say, from different beans) will return the same instance of the Supplier.
The first method is more flexible though, because it allows to keep the definition of the supplier and class A in different configuration files, the second way assumes that they're both defined in the same #Configuration.
Update (based on Op's Comments)
With field injection it will work just the same:
public class A {
#Autowired
private Supplier<Set<String>> sup;
public Set<String> getSet() {
return this.sup.get();
}
}
#Configuration
public class SampleConfig {
#Bean
public Supplier<Set<String>> set () {
return () -> Set.of("a","b", "c");
}
#Bean
public A a () {
return new A();
}
// this is called right before the application gets started (after all the injections are done - this is just for the sake of illustration)
#EventListener(ApplicationReadyEvent.class)
public void onReady(ApplicationReadyEvent evt) {
A a = evt.getApplicationContext().getBean(A.class);
System.out.println(a.getSet()); // this will return your set
}
}

Guice inject an object to a class constructor

I just started looking at Guice for a new project. I have something like this
the ConfigImpl class ans Config interface
interface Config{...}
class ConfigImpl implements Config {
private static final Map<> propMap;
public ConfigImpl(Map<> propMap) {
this.propMap = someProps;
}
}
Guice injection I came up with
public class MyInjector extends AbstractModule {
protected void configure() {
bind(Config.class).to(ConfigImpl.class)
}
}
and finally
public SomeClass {
Config someConfig;
Injector injector = Guice.createInjector(new MyInjector());
someConfig = injector.getInstance(Config.class);
}
Now I am very confused as I can't find a way to pass propMap into ConfigImpl class. I'd like to know the proper way of doing it in Guice. Thanks!
You should inject propMaps from your module:
public class MyInjector extends AbstractModule {
private final Map<String,String> mapProps;
public MyInjector(Map<String,String> mapProps) {
this.mapProps = mapProps;
}
protected void configure() {
bind(Config.class).to(ConfigImpl.class).in(Scope.SINGLETON); // You most than likely want this
bind(new TypeLiteral<Map<String,String>>() {}).toInstance(mapProps); // binding for the map.
}
}
And use it like this:
public class SomeClass {
void doSomething() {
Map<String,String> mapProps = ... ;
Injector injector = Guice.createInjector(new MyInjector(mapProps));
Config someConfig = injector.getInstance(Config.class);
}
}
Also, you should fix your ConfigImpl class:
class ConfigImpl implements Config {
private final Map<String,String> propMap;
#Inject // mandatory since you use a non-default constructor
public ConfigImpl(Map<String,String> propMap) { // add the generic type of the map
this.propMap = propMap;
}
}

Defining bean with two possible implementations

So far, I had a very simple bean definition that looked like this:
#Bean
#Conditional(value=ConditionClass.class)
SomeInterface myMethodImpl(){
return new ImplementationOne();
}
However, I now have situation where additional implementation class has been added, let's call it ImplementationTwo, which needs to be used instead of ImplementationOne when the option is enabled in configuration file.
So what I need is something like this:
#Bean
#Conditional(value=ConditionClass.class)
SomeInterface myMethodImpl(){
return context.getEnvironment().getProperty("optionEnabled") ? new
ImplementationOne() : new ImplementationTwo();
}
Basically a way to instantiate correct implementation at bean definition time based on the configuration value. Is this possible and can anyone please provide an example? Thanks
It is possible to implement this without using #Conditional.
Assuming you have a Interface SomeInterface and two implementations ImplOne ImplTwo:
SomeInterface.java
public interface SomeInterface {
void someMethod();
}
ImplOne.java
public class ImplOne implements SomeInterface{
#Override
public void someMethod() {
// do something
}
}
ImplTwo.java
public class ImplTwo implements SomeInterface{
#Override
public void someMethod() {
// do something else
}
}
Then you can control which implementation is used in a configuration class like this:
MyConfig.java
#Configuration
public class MyConfig {
#Autowired
private ApplicationContext context;
#Bean
public SomeInterface someInterface() {
if (this.context.getEnvironment().getProperty("implementation") != null) {
return new ImplementationOne();
} else {
return new ImplementationTwo();
}
}
}
Make sure that the component scan of spring finds MyConfig. Then you can use #Autowired to inject the right implementation anywhere else in your code.
I think you are doing it wrong.
You should use #Conditional() on your implementation and not on your Interface.
Here is how I would do it :
The interface you will use on your code.
MyInterface.java
public interface MyInterface {
void myMethod();
}
The first implementation :
MyInterfaceImplOne.java
#Bean
#Conditional(MyInterfaceImplOneCondition.class)
public class MyInterfaceImplOne implements MyInterface {
void myMethod(){
// dosmthg
}
}
MyInterfaceImplOneCondition.java
public class MyInterfaceImplOneCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().getProperty("optionEnabled")
}
}
And for the 2nd implementation :
MyInterfaceImplTwo.java
#Bean
#Conditional(MyInterfaceImplTwoCondition.class)
public class MyInterfaceImplTwo implements MyInterface {
void myMethod(){
// dosmthg 2
}
}
MyInterfaceImplTwoCondition.java
public class MyInterfaceImplTwoCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return !context.getEnvironment().getProperty("optionEnabled")
}
}
In that case, you now just have to call the interface, and Spring will inject the bean corresponding to the right condition.
Hope it is what you are looking for, and I was clear enough!

Pass constant class as argument and store it

Psuedo-code
The snippets provided are to be taken as psuedo-code. I am open to if there is a different solution that is the standard way to solve this problem.
This is about the expected usage:
Some clarification:
One, and only one configuration will be used per application. It will not be changed during runtime.
Main.java can not allow #Override.
Configuration.java can not be an Interface as default values should be given to fields not overridden.
Configuration.java will grow quite substantially from its two current fields. Rendering the builder-pattern very messy to work with.
Configuration.java
public class Configuration
{
public static int getFoo () { return 1; }
public static int getBar () { return 2; }
}
UserDefinedConfiguration.java
public class UserDefinedConfiguration extends Configuration
{
#Override
public static int getFoo () { return 3; }
}
Main.java
public final class Main {
private final Configuration config;
// default configuration
public Main () {
this (Configuration.class);
}
// user-defined configuration
public Main (Class<? extends Configuration> config) {
this.config = config;
}
// dummy-test
public void printFoo () {
System.out.println(config.getFoo());
}
}
Now to the main question, how to accomplish this? If no (or Configuration is passed) getFoo() should return 1, if the UserDefinedConfiguration is passed then 3.
One way to accomplish it is to store an instance of Configuration. However, it feels redundant when all the getters are static. It doesn't make much sense to not have them as static either.
Note: This is taken into account.
Unless playing with dirty reflection, I'm afraid you'll have to work with instances instead of classes. From #JonSkeet:
A singleton allows access to a single created instance - that instance
(or rather, a reference to that instance) can be passed as a parameter
to other methods, and treated as a normal object.
A static class allows only static methods.
This is exactly what you're trying to do: passing the configuration as a parameter.
I would create an abstract class defining the default values:
public abstract class Configuration {
public int getFoo() { return 1; }
public int getBar() { return 2; }
}
Then, one singleton per concrete configuration:
public final class DefaultConfiguration extends Configuration {
public static final Configuration INSTANCE = new DefaultConfiguration();
private DefaultConfiguration() {}
// nothing to override, use the default values
}
public final class UserDefinedConfiguration extends Configuration {
public static final Configuration INSTANCE = new UserDefinedConfiguration();
private UserDefinedConfiguration() {}
#Override public int getFoo() { return 3; } // specific `foo` value
}
Finally, in your Main:
public class Main {
private final Configuration config;
public Main() { this(DefaultConfiguration.INSTANCE); }
public Main(Configuration config) { this.config = config; }
}
Plus, note that Java 8 allows default methods implementations within interfaces; Configuration could then be an interface:
public interface Configuration {
default int getFoo() { return 1; }
default int getBar() { return 2; }
}
So essentially, you need polymorphism on a type rather than an instance. In Java this is usually done with generic types:
class GenericMain<T extends Configuration>
{
private final T config;
}
and because Java doesn't allow default generic arguments, you have to define another class to specify the default:
class DefaultMain extends GenericMain<Configuration>
{
}
These match one-to-one to your Main () and Main (Class<? extends Configuration> config) constructors.
Alternatively, you could store an instance of Configuration and do something like this:
public class Configuration
{
private final int foo = 1;
private final int bar = 2;
public final int getFoo () { return foo; }
public final int getBar () { return bar; }
public Configuration () {}
protected Configuration (int foo) {
this.foo = foo;
}
}
public class UserDefinedConfiguration extends Configuration
{
public UserDefinedConfiguration() {
super(3);
}
}

Correct way to parametrize a generic java event handler

I have some code as follows (excerpt):
public interface Event<S> {
S getSource();
}
public interface Subscriber<E> {
void update(E event);
}
public interface EventPublisher<S, E extends Event<S>> {
void addSubscription(S source, Subscriber<E> subscriber);
void removeSubscription(S source, Subscriber<E> subscriber);
}
public class SubscriptionManager<S, E extends Event<S>> implements Subscriber<E>, EventPublisher<S, E> {
...
}
public class MyEvent implements Event<MyEventSource> {
...
}
This all works fine, however, my problem is when I try something like this:
public class MyEventHandler {
private final SubscriptionManager<Class<? extends Event<?>>, ? extends Event<?>> subscriptionManager = new SubscriptionManager<>();
Subscriber<? extends Event<?>> subscriber = ...;
subscriptionManager.addSubscription(MyEvent.class, subscriber); **// Compile error**
}
I get the following error:
The method addSubscription(Class<? extends Event<?>>, Subscriber<capture#3-of ? extends Event<?>>) in the type SubscriptionManager<Class<? extends Event<?>>,capture#3-of ? extends Event<?>> is not applicable for the arguments (Class<MyEvent>, Subscriber<capture#5-of ? extends Event<?>>)
Can anyone tell me what's wrong?
Thanks
To be honest with you I think there's some design error in your code. It almost looks like a perfectly designed pattern, but something doesn't add up. You can probably omit half of generic parameters and make it more straightforward.
Please consider the code below. Entire framework is parametrized by a single parameter. Everything compiles and there are no raw types used.
Also, note that MyEvent is never used in the framework definition. It's a convenience class.
You can safely invoke subscriptionManager.update(new MyEvent()); somewhere in your code.
More complicated arrangements are possible too, but I believe that's the one you need.
Please let me know if that works for you.
static interface Event<S> {
S getSource();
}
static interface Subscriber<S> {
void update(Event<S> event);
}
static interface EventPublisher<S> {
void addSubscription(Class<S> sourceClass, Subscriber<S> subscriber);
void removeSubscription(Class<S> sourceClass, Subscriber<S> subscriber);
}
static class SubscriptionManager<S> implements Subscriber<S>, EventPublisher<S> {
public void addSubscription(Class<S> sourceClass, Subscriber<S> subscriber) {
}
public void removeSubscription(Class<S> sourceClass, Subscriber<S> subscriber) {
}
public void update(Event<S> event) {
}
}
static class MyEvent implements Event<String> {
public String getSource() {
return null;
}
}
static class MyEventHandler {
private final SubscriptionManager<String> subscriptionManager = new SubscriptionManager<String>();
public MyEventHandler() {
Subscriber<String> subscriber = null;
subscriptionManager.addSubscription(String.class, subscriber);
}
}

Categories