Is there an equivalent injecting Guice Providers in Simple Injector?
I need to inject a dependency into a constructor that will let me create as many instances of a dependency as needed. In guice it would look like this...
public class RealBillingService implements BillingService {
private final Provider<CreditCardProcessor> processorProvider;
private final Provider<TransactionLog> transactionLogProvider;
#Inject
public RealBillingService(Provider<CreditCardProcessor> processorProvider,
Provider<TransactionLog> transactionLogProvider) {
this.processorProvider = processorProvider;
this.transactionLogProvider = transactionLogProvider;
}
public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
// each call to get creates a new instance in Guice as per scope configs
CreditCardProcessor processor = processorProvider.get();
TransactionLog transactionLog = transactionLogProvider.get();
/* use the processor and transaction log here */
}
}
So perhaps a C# equivalent could be this inside SimpleInjector?
private readonly MailSender _mailSenderProvider;
public MailService(Func<MailSender> mailSenderProvider)
{
_mailSenderProvider = mailSenderProvider;
}
public void SendMail()
{
var mailSender = _mailSenderProvider.Invoke();
mailSender.SendSomeMail("Hello world");
}
I tried injecting Func in my real code and got this...
{"No registration for type BootStrapper could be found and an implicit registration could not be made. The constructor of type BootStrapper contains the parameter of type Func with name 'storeType' that is not registered. Please ensure Func is registered in the container, or change the constructor of BootStrapper."}
You need to explicitly configure factory delegates with Simple Injector (see here)
var container = new Container();
container.Register<MailSender>();
container.RegisterSingle<Func<MailSender>>(() => container.GetInstance<MailSender>());
You may want to consider separating concerns by adding a new abstraction. If you define an IMailSender you can then create a MailSenderProxy that is responsible for ensuring a new MailSender instance for each message.
public interface IMailSender {
void Send(string message);
}
public class MailSender : IMailSender {
public void Send(string message) {
}
}
public class MailSenderProxy : IMailSender {
private readonly Func<IMailSender> mailSenderFactory;
public MailSenderProxy(Func<IMailSender> mailSenderFactory) {
this.mailSenderFactory = mailSenderFactory;
}
public void Send(string message) {
this.mailSenderFactory().Send(message);
}
}
This abstracts away the requirement of creating a new MailSender for each mail (this is possibly not something the MailService should know about)
public class MailService {
private readonly IMailSender sender;
public MailService(MailSender sender) {
this.sender = sender;
}
public void SendMail() {
this.sender.Send("Message");
}
}
The Container configuration would look something like this
var container = new Container();
container.Register<MailSender>();
container.RegisterSingle<Func<IMailSender>>(() =>
container.GetInstance<MailSender>());
container.Register<IMailSender, MailSenderProxy>();
container.Verify();
I found the following example in the SimpleInjector docs
http://simpleinjector.readthedocs.org/en/latest/howto.html#register-factory-delegates
public static void AllowResolvingFuncFactories(this ContainerOptions options)
{
options.Container.ResolveUnregisteredType += (s, e) =>
{
var type = e.UnregisteredServiceType;
if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(Func<>))
{
return;
}
Type serviceType = type.GetGenericArguments().First();
InstanceProducer registration = options.Container.GetRegistration(serviceType, true);
Type funcType = typeof(Func<>).MakeGenericType(serviceType);
var factoryDelegate = Expression.Lambda(funcType,
registration.BuildExpression()).Compile();
e.Register(Expression.Constant(factoryDelegate));
};
}
Then on my container I call this...
// Allow types of Func<T> to be resolved
container.Options.AllowResolvingFuncFactories();
// 3. Optionally verify the container's configuration.
container.Verify();
Now I can inject Func< MyClass > and when I invoke the Func it returns as many instances as I want of that type.
All thanks to C# reified types and Simpleinjector's awesome api!
Related
We have used Google Guice framework for dependency injection. I need to create multiple insatnce of an interface in java.
The execution starts from here: KfhRecordValidator.java class in the below code:
public class KfhRecordValidator implements RequestHandler<Request, Response> {
public Response handleRequest(Request request, Context context)
{
// Resolve the necessary dependencies, and process the request.
Injector injector = Guice.createInjector(new
DependencyModule());
Processor processor =
injector.getInstance(Processor.class);
return processor.process(request, context);
}}
The process class is having reference of RecordValidationHelper class and the injection is through constructor.
IRecordValidationService.java is an interface that is having validate method.
public interface IRecordValidationService {
void validate(Record record) throws ValidationException;}
class processor is having one method called process that is being called in RecordValidationHelper class.
class Processor {
private final RecordValidationHelper recordValidationHelper;
#Inject
#SuppressWarnings({"WeakerAccess"})
public Processor(IRecordValidationService recordValidationService,
IRecordService<ErrorRecord> recordService,
S3UtilsInterface s3Utils, IEnvironmentVariableReader
environmentVariableReader) {
this.recordValidationHelper = new
RecordValidationHelper(recordValidationService);
this.errorRecordHelper = new
ErrorRecordHelper(recordService, environmentVariableReader);
}
public Response process(Request request, #SuppressWarnings("unused") Context context) {
// Validate records
List<LambdaRecord> records = recordValidationHelper.processRecords(request.getRecords());}
Class DependencyModule.java extneds AbstractModule class of Guice injection that is having configure method.
class DependencyModule extends AbstractModule {
#Override
protected void configure() {
String validationType = System.getenv("ValidationType");
validationType= validationType.toLowerCase(Locale.ENGLISH);
String valType[]= validationType.split(",");
int length= valType.length;
for(int i=0;i<length;i++){
switch(valType[i]){
case "json":
bind(IRecordValidationService.class).to(JsonValidationService.class);
break;
case "avro":
bind(IRecordValidationService.class).to(AvroSchemaValidationService.class);
break;
case "clientlogging":
bind(IRecordValidationService.class).to(ClientLoggingValidationService.class);
break;
case "servicelogs":
bind(IRecordValidationService.class).to(ServiceLoggingValidationService.class);
break;
default:
throw new UnsupportedOperationException(String.format("Encountered an unsupported ValidationType of '%s'.", valType[i]));
}
} } }
SO the issue is if I am getting validation type as AVRO, JSON then it will bind IRecordValidationService to respective JsonValidationService/AvroSchemaValidationService class. I need to create multiple instance for that but it supports only once instance at a time.
Below is the RecordValidationHelper.java class
public class RecordValidationHelper extends AbstractModule {
private final IRecordValidationService recordValidationService;
#Inject
public RecordValidationHelper(IRecordValidationService recordValidationService) {
this.recordValidationService = recordValidationService;
}
public List processRecords(List requestRecords) {
List records = new ArrayList<>();
for (RequestRecord record : requestRecords) {
try {
Record domainRecord = new Record();
domainRecord.setKey(record.getRecordId());
domainRecord.setValue(new String(Base64.getDecoder().decode(record.getData())));
// Use the injected logic to validate the record.
((IRecordValidationService)
recordValidationService).validate(domainRecord);}
catch (ValidationException ex) {}}}
return records;}
Anyone having any idea about how it should be implemented to get multiple instance suitable for this.
Use #Named bindings
In your DependencyModule, bind using names:
bind(IRecordValidationService.class)
.annotatedWith(Names.named("json"))
.to(JsonValidationService.class);
bind(IRecordValidationService.class)
.annotatedWith(Names.named("avro"))
.to(AvroSchemaValidationService.class);
bind(IRecordValidationService.class)
.annotatedWith(Names.named("clientlogging"))
.to(ClientLoggingValidationService.class);
bind(IRecordValidationService.class)
.annotatedWith(Names.named("servicelogs"))
.to(ServiceLoggingValidationService.class);
Then in your injectee:
#Inject
public RecordValidationHelper(
#Named("json") IRecordValidationService jsonValidation,
#Named("avro") IRecordValidationService avroValidation,
#Named("clientlogging") IRecordValidationService clientLoggingValidation,
#Named("servicelogs") IRecordValidationService serviceLogsValidation,
) {
this.jsonValidation = jsonValidation;
this.avroValidation = avroValidation;
this.clientLoggingValidation = clientLoggingValidation;
this.serviceLogsValidation = serviceLogsValidation;
}
See Guice's BindingAnnotation wiki page for more info.
I want implement strategy design pattern in spring boot application. I create BeanPostProcessor for construct strategy resolver:
#Component
public class HandlerInAnnotationBeanPostProcessor implements BeanPostProcessor {
private final UnpHandlersResolver unpHandlersResolver;
public HandlerInAnnotationBeanPostProcessor(UnpHandlersResolver unpHandlersResolver) {
this.unpHandlersResolver = unpHandlersResolver;
}
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Annotation[] annotations = bean.getClass().getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof HandlerIn) {
if (bean.getClass() != UnpHandler.class)
throw new RuntimeException("Not UnpHandler bean annotated by HandlerIn");
SmevMessageType[] type = ((HandlerIn) annotation).type();
for (SmevMessageType smevMessageType : type) {
unpHandlersResolver.setHandler(smevMessageType, (UnpHandler) bean);
}
}
}
return bean;
}
}
And I create resolver:
#Slf4j
#Component
public class UnpHandlersResolverImpl implements UnpHandlersResolver {
private Map<SmevMessageType, UnpHandler> map = new HashMap<>();
#Override
public void setHandler(SmevMessageType messageType, UnpHandler unpHandler) {
map.put(messageType, unpHandler);
}
#Override
public UnpHandler getUnpHandler(SmevMessageType type) {
UnpHandler sendRequestHandler = map.get(type);
if (sendRequestHandler == null)
throw new IllegalArgumentException("Invalid SendRequestHandler type: " + type);
return sendRequestHandler;
}
}
My BeanPostProcessor scan all beans with annotation HandlerIn and add to resolver's mup. I think it's wrong to do that:
unpHandlersResolver.setHandler(smevMessageType, (UnpHandler) bean);
But I not understand how can I add find beans to resolver. Before this implementation I faind beans in #Postconstruct method of resolver like:
context.getBeansWithAnnotation(HandlerIn.class);
But in this solution I have context in resolver and I think is bad.
Tell me how to properly implement what I want? In short, I want to have a set of classes that implement different behaviors. And the class that controls them. Give the class a parameter so that he chooses the right strategy and gives it to me. Like this:
Handler handler = handlersResolver.getHandler(messageType);
Result result = handler.somthing(param);
I'm going to try to make a simple example.
Interface Greeting {
void sayHello();
String getSupportedLanguage();
}
Then you have X number of implementations and you can loop through them in your "resolver"'s constructor to build the map. (I've seen this called a Proxy or a Decorator in code though, i.e. GreetingProxy or GreetingDecorator)
#Service
public GreetingResolver {
private Map<String, Greeting> languageToGreetingMap = new HashMap<>();
#Autowired
public GreetingResolver(List<Greeting> greetings) {
for (Greeting greeting : greetings) {
languageToGreetingMap.put(greeting.getSupportedLanguage(), greeting);
}
}
public void sayGreetingForLanguage(String language) {
languageToGreetingMap.get(language).sayHello();
}
}
This is a basic example of how one can do the strategy pattern in Spring. Every interface implementation of "Greeting" only knows about itself and what it can support. We then autowire all implementations in a list and loop through to create the map once and then during runtime only the relevant entry from the map in retrieved and used.
Note: this was typed "free hand" directly in the web page so please forgive any typos in the code.
My Spring Boot application contains several #KafkaListeners, and each listener performs the same steps before and after actually processing the payload: Validate the payload, check whether the event has been processed already, check whether it's a tombstone (null) message, decide whether processing should be retried in case of failure, emit metrics, etc.
These steps are currently implemented in a base class, but because the topics passed to #KafkaListener must be constant at runtime, the method annotated with #KafkaListener is defined in the subclass, and does nothing but pass its parameters to a method in the base class.
This works just fine, but I wonder if there's a more elegant solution. I assume my base class would have to create a listener container programmatically, but after a quick look at KafkaListenerAnnotationBeanPostProcessor, it seems to be quite involved.
Does anyone have any recommendadtions?
Having stumbled upon this question while looking to implement something similar, I first started with Artem Bilan's answer. However this did not work because annotations by default are not inherited in child classes unless they are themselves annotated with #Inherited. Despite this there may yet be a way to make an annotation approach work and I will update this answer if and when I get it to work. Thankfully though I have achieved the desired behavour using programtic registration of the Kafka listeners.
My code is something like the following:
Interface:
public interface GenericKafkaListener {
String METHOD = "handleMessage";
void handleMessage(ConsumerRecord<String, String> record);
}
Abstract Class:
public abstract class AbstractGenericKafkaListener implements GenericKafkaListener {
private final String kafkaTopic;
public AbstractGenericKafkaListener(final String kafkaTopic) {
this.kafakTopic = kafkaTopic;
}
#Override
public void handleMessage(final ConsumerRecord<String, String> record) {
//do common logic here
specificLogic(record);
}
protected abstract specificLogic(ConsumerRecord<String, String> record);
public String getKafkaTopic() {
return kafkaTopic;
}
}
We can then programtically register all beans of type AbstractGenericKafkaListener in a KafkaListenerConfigurer:
#Configuration
public class KafkaListenerConfigurataion implements KafkaListenerConfigurer {
#Autowired
private final List<AbstractGenericKafkaListener> listeners;
#Autowired
private final BeanFactory beanFactory;
#Autowired
private final MessageHandlerMethodFactory messageHandlerMethodFactory;
#Autowired
private final KafkaListenerContainerFactory kafkaListenerContainerFactory;
#Value("${your.kafka.consumer.group-id}")
private String consumerGroup;
#Value("${your.application.name}")
private String service;
#Override
public void configureKafkaListeners(
final KafkaListenerEndpointRegistrar registrar) {
final Method listenerMethod = lookUpMethod();
listeners.forEach(listener -> {
registerListenerEndpoint(listener, listenerMethod, registrar);
});
}
private void registerListenerEndpoint(final AbstractGenericKafkaListener listener,
final Method listenerMethod,
final KafkaListenerEndpointRegistrar registrar) {
log.info("Registering {} endpoint on topic {}", listener.getClass(),
listener.getKafkaTopic());
final MethodKafkaListenerEndpoint<String, String> endpoint =
createListenerEndpoint(listener, listenerMethod);
registrar.registerEndpoint(endpoint);
}
private MethodKafkaListenerEndpoint<String, String> createListenerEndpoint(
final AbstractGenericKafkaListener listener, final Method listenerMethod) {
final MethodKafkaListenerEndpoint<String, String> endpoint = new MethodKafkaListenerEndpoint<>();
endpoint.setBeanFactory(beanFactory);
endpoint.setBean(listener);
endpoint.setMethod(listenerMethod);
endpoint.setId(service + "-" + listener.getKafkaTopic());
endpoint.setGroup(consumerGroup);
endpoint.setTopics(listener.getKafkaTopic());
endpoint.setMessageHandlerMethodFactory(messageHandlerMethodFactory);
return endpoint;
}
private Method lookUpMethod() {
return Arrays.stream(GenericKafkaListener.class.getMethods())
.filter(m -> m.getName().equals(GenericKafkaListener.METHOD))
.findAny()
.orElseThrow(() ->
new IllegalStateException("Could not find method " + GenericKafkaListener.METHOD));
}
}
How about this:
public abstract class BaseKafkaProcessingLogic {
#KafkaHandler
public void handle(Object payload) {
}
}
#KafkaListener(topics = "topic1")
public class Topic1Handler extends BaseKafkaProcessingLogic {
}
#KafkaListener(topics = "topic2")
public class Topic2Handler extends BaseKafkaProcessingLogic {
}
?
I needed the same functionality and came up with solution close to Artem Bilan answer. Yes, #KafkaHandler annotation is not inherited by the child classes but defined in interface it is. Here is the solution:
interface AbstractKafkaListener<T> {
default Class<T> getCommandType() {
TypeToken<T> type = new TypeToken<>(getClass()) {};
return (Class<T>) type.getRawType();
}
#KafkaHandler
default void handle(String message) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
T value = objectMapper.readValue(message, getCommandType());
handle(value);
}
void handle(T message);
}
The class should implement the handle method only:
#Component
#KafkaListener(topics = "my_topic")
public class KafkaListenerForMyCustomMessage implements AbstractKafkaListener<MyCustomMessage> {
#Override
public void handle(MyCustomMessage message) {
System.out.println(message);
}
}
The 2 implemented methods in the interface should be private/protected but because they are in interface this cannot be done. default methods are always public. Actually, all methods defined in interface are always public.
I use this solution to dynamically parse the message from kafka (received in String) to the custom class.
getCommandType method returns the class of the T generic param. TypeToken is from Google Guava package.
I am using java websockets in play framework 2.6 and having hard time figuring out Guice DI. Below I am injecting DbService (which perform some db operations) but I am getting DbService as null and throwing NPE at line
User user = dbService.findByName(inEvent.getUsername());
dbService is null. I am not sure why its not injecting DbService. Although this work when I don't use it via akka actors. I do bind DbService to its implementation.
Actor
public class TestActor extends AbstractActor {
#Inject
private DbService dbService;
private ActorRef out;
public static Props props(final ActorRef out) {
return Props.create(TestActor.class, out);
}
public TestActor(ActorRef out) {
this.out = out;
}
#Override
public Receive createReceive() {
return receiveBuilder()
.match(InEvent.class, inEvent -> {
System.out.println(inEvent.getUsername());
User user = dbService.findByName(inEvent.getUsername());
System.out.println(user.getFirstName());
out.tell("userName is ", self());
}
)
.build();
}
}
Controller
public class Application extends Controller {
public WebSocket TestWebSocket() {
return WebSocket.json(InEvent.class).acceptOrResult(request -> {
final Token token = verifyToken(request());
if (token == null) {
return CompletableFuture.completedFuture(F.Either.Left(forbidden()));
}
return CompletableFuture.completedFuture(
F.Either.Right(ActorFlow.actorRef(out -> TestActor.props(out), actorSystem, materializer)));
});
}
}
Your actor will be constructed based on the parameters used in Props.create().
In your example:
Props.create(Class<TestActor>, ActorRef);
Will match the constructor in the TestActor.class with one argument of type ActorRef, and that constructor will be calle with the arguments that you provide.
You can change your constructor signature and the props method like this:
...
public static Prop props(ActorRef out, DBServide db) {
return Props.create(TestActor.class, out, db);
}
...
public TestActor(ActorRef out, DBService db) {
this.out = out;
this.dbService = db;
}
...
With this, the constructor TestActor(ActorRef, DBService) will be used and you will get the instance of DBService used when you called the static method props.
In Spring 4.2+, we can use #EventListener annotation with a "condition" expression.
In my scenario, I need to match the id of the event object with a regular expression that is configured in a .properties file.
However, it seems impossible to reference any bean's property or method from the condition's regular expression, as the root context seems to be the event object itself.
So far, I have an abstract class, that sets the event id pattern property based on the class name. The goal is to make the implementation of each Event Listener as clean and simple as possible.
#Service
#PropertySource(value = "classpath:subscriberEventMapping.properties")
public abstract class AbstractEventHandler implements IEventHandler {
private String eventIdPattern;
#Autowired
Environment env;
#Autowired(required = true)
public void configureEventIdPattern() {
String simpleClassName = this.getClass().getSimpleName();
String resolvedEventIdPattern = env.getProperty(
simpleClassName.substring(0,1).toLowerCase() +
simpleClassName.substring(1, simpleClassName.length()));
this.eventIdPattern = resolvedEventIdPattern == null ? ".*" : resolvedEventIdPattern;
}
public String getEventIdPattern() {
return eventIdPattern;
}
}
The properties file looks like this:
regExpEventHandler=^(901|909|998|1000)$
dummyEventHandler=^([1-9][0-9]{0,2}|1000)$
And then, I have a sample Event Listener that extends the above Abstract class:
#Service
public class RegExpEventHandler extends AbstractEventHandler {
#Log
private ILog logger;
#Override
#EventListener(condition = "#event.eventid matches #regExpEventHandler.getEventIdPattern()")
public void onEvent(Event event) {
logger.debug("RegExpEventHandler processing : {} with event pattern : {}", event, getEventIdPattern());
}
}
The problem is that the expression
"#event.eventid matches #regExpEventHandler.getEventIdPattern()"
does not work, because the bean "#regExpEventHandler" cannot be found in the context used by the #EventListener.
Is there a way to access methods or properties of an existing Spring Bean here? Any other better approach for this scenario ?
I know I can easily access STATIC constants or methods by using something like:
#event.eventid matches T(my.package.RegExpEventHandler.MY_CONSTANT)
But a String constant (static final) cannot be initialized from a properties file using a #Value expression.
Using NON-FINAL static constants can work, but then EACH Event Listener needs to add boiler-plate to initialize the static constant from a non-static variable using a #Value expression, which we want to avoid.
Thanks a lot in advance !
It works for me - I looked at the EventExpressionEvaluator and saw that it added a bean resolver to the evaluation context...
public EvaluationContext createEvaluationContext(ApplicationEvent event, Class<?> targetClass,
Method method, Object[] args, BeanFactory beanFactory) {
Method targetMethod = getTargetMethod(targetClass, method);
EventExpressionRootObject root = new EventExpressionRootObject(event, args);
MethodBasedEvaluationContext evaluationContext = new MethodBasedEvaluationContext(
root, targetMethod, args, getParameterNameDiscoverer());
if (beanFactory != null) {
evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory));
}
return evaluationContext;
}
So I wrote a quick test...
#SpringBootApplication
public class So43225913Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(So43225913Application.class, args);
context.publishEvent("foo");
}
#EventListener(condition = "#bar.accept(event)")
public void listen(Object event) {
System.out.println("handler:" + event);
}
#Bean
public Bar bar() {
return new Bar();
}
public static class Bar {
public boolean accept(Object o) {
System.out.println("bar:" + o);
return true;
}
}
}
and it works just fine...
bar:org.springframework.context.PayloadApplicationEvent[...
handler:foo
(This was with 4.3.7; boot 1.5.2).