IoC container struggles with generics - catel

I have an existing program with some plugin infrastructure that currently relies on plugin classes having parameterless constructors. I'd like to offer plugin authors the opportunity to just require some infrastructure from my program by specifying parameters for the constructor.
Internally, I use some generic wrapper class to encapsulate the plugin's classes and to make them behave to the rest of my program like older pre-plugin era internal classes.
I have some placeholder here representing my infrastructure:
public interface IInfrastructure
{
}
public class Infrastructure : IInfrastructure
{
}
Some plugin interface specification:
public interface IPlugin
{
}
the plugin implementation requiring my infrastructure:
public class Plugin : IPlugin
{
public Plugin(IInfrastructure _)
{
}
}
and my generic wrapper class expecting some plugin class
public class PluginWrapper<TImpl> where TImpl: class, IPlugin
{
public PluginWrapper(TImpl _)
{
}
}
After registering the involved types:
ServiceLocator.Default.RegisterType<IInfrastructure, Infrastructure>(RegistrationType.Transient);
ServiceLocator.Default.RegisterType(typeof(Plugin),typeof(Plugin), RegistrationType.Transient);
var wrapperType = typeof(PluginWrapper<>).MakeGenericType(typeof(Plugin));
ServiceLocator.Default.RegisterType(wrapperType, wrapperType,RegistrationType.Transient);
I find out that I can resolve the "inner" plugin type:
Assert.NotNull(ServiceLocator.Default.ResolveType<Plugin>());
but I can't resolve the "Wrapper" type.
Assert.NotNull(ServiceLocator.Default.ResolveType<PluginWrapper<Plugin>>());
Am I hitting a limitation of Catel's IoC container, or am I doing something wrong?

When not using the generic registration method, I passed the registration type in the position of the "tag" parameter by accident.
So, changing the registration part to this version:
ServiceLocator.Default.RegisterType<IInfrastructure, Infrastructure>(RegistrationType.Transient);
ServiceLocator.Default.RegisterType(typeof(Plugin),typeof(Plugin),registrationType:RegistrationType.Transient);
var wrapperType = typeof(PluginWrapper<>).MakeGenericType(typeof(Plugin));
ServiceLocator.Default.RegisterType(wrapperType, wrapperType, registrationType:RegistrationType.Transient);
fixes the problem and everything goes as expected.

Related

Inject different implementations based on application property in Quarkus

I have a Repository interface that has two implementations. One reads data from a locally stored CSV file while the other reads from an Amazon Dynamo DB. I would like to be able to switch between which implementation I'm using based on an application property or custom build profile. I would normally use a Factory to retrieve the correct class at runtime, but I would like to do this with injection if possible.
I found a similar question using Spring boot but couldn't find an equivalent that would work in Quarkus Spring choose bean implementation at runtime
I also tried implementing a Configuration class similar to what is found in the docs here but again didn't have much luck. https://quarkus.io/guides/cdi-reference#default_beans
It feels like I'm missing something obvious so any pointers would be much appreciated.
Here is a simple example of my classes:
#ApplicationScoped
public class ExampleService {
#Inject
ExampleRepository repository;
public List<Data> retrieveData() {
return repository.retrieveData();
}
}
public interface ExampleRepository {
List<Data> retrieveData();
}
#ApplicationScoped
public class DynamoRepository implements ExampleRepository {
#Override
public List<Data> retrieveData() {
//Get Data from DynamoDb
}
}
#ApplicationScoped
public class CsvRepository implements ExampleRepository {
#Inject
CsvBeanHandler csvBeanHandler;
#Inject
LocalFileReader fileReader;
#Override
public List<Data> retrieveData() {
// Get data from CSV
}
}
I currently also have the following in my application.yml:
com:
example:
application:
storage-type: 'CSV' # OR AMAZON_DYNAMO_DB
It looks like they've added this directly to the documentation:
https://quarkus.io/guides/cdi-reference#declaratively-choose-beans-that-can-be-obtained-by-programmatic-lookup
I feel a bit guilty pasting this much, but it's the SO way.
I can add that it is NOT like a Guice 'binding'; BOTH classes will be instantiated, but only one will be injected. Also unlike Guice, you cannot inject the interface (or I did it wrong) - you have to do what's shown below, with Instance.
Personally I just use constructor injection and then drop the value of the Instance wrapper into a final field, so I'm not crying about the extra step. I do miss the power and explicit bindings possible with Modules ala Guice, but the simplicity here has its own value.
5.16. Declaratively Choose Beans That Can Be Obtained by Programmatic Lookup
It is sometimes useful to narrow down the set of beans that can be
obtained by programmatic lookup via javax.enterprise.inject.Instance.
Typically, a user needs to choose the appropriate implementation of an
interface based on a runtime configuration property.
Imagine that we have two beans implementing the interface
org.acme.Service. You can’t inject the org.acme.Service directly
unless your implementations declare a CDI qualifier. However, you can
inject the Instance instead, then iterate over all
implementations and choose the correct one manually. Alternatively,
you can use the #LookupIfProperty and #LookupUnlessProperty
annotations. #LookupIfProperty indicates that a bean should only be
obtained if a runtime configuration property matches the provided
value. #LookupUnlessProperty, on the other hand, indicates that a bean
should only be obtained if a runtime configuration property does not
match the provided value.
#LookupIfProperty Example
interface Service {
String name();
}
#LookupIfProperty(name = "service.foo.enabled", stringValue = "true")
#ApplicationScoped
class ServiceFoo implements Service {
public String name() {
return "foo";
}
}
#ApplicationScoped
class ServiceBar implements Service {
public String name() {
return "bar";
}
}
#ApplicationScoped
class Client {
#Inject
Instance<Service> service;
void printServiceName() {
// This will print "bar" if the property "service.foo.enabled" is NOT set to "true"
// If "service.foo.enabled" is set to "true" then service.get() would result in an AmbiguousResolutionException
System.out.println(service.get().name());
}
}
If your request is to bind at startup time the right implementation based on a configuration property, I suppose your problem may be resolved used #Produces annotation:
public class ExampleRepositoryFactory {
#Config("storage-type")
String storageType;
#Produces
public ExampleRepository dynamoInstance() {
return storageType == "CSV" ? new CsvRepository() : new DynamoRepository();
}
}

Guice, Groovy, #Canonical and inheritance not playing nicely together

I have the following Groovy classes:
enum Protocol {
File,
Ftp,
Sftp,
Http,
Https
}
#Canonical
abstract class Endpoint {
String name
Protocol protocol
}
#Canonical
#TupleConstructor(includeFields=true, includeSuperFields=true)
class LocalEndpoint extends Endpoint {
}
class MyAppModule extends AbstractModule {
#Override
protected void configure() {
// Lots of stuff...
}
// Lots of other custom providers
#Provides
Endpoint providesEndpoint() {
new LocalEndpoint('fileystem', Protocol.File)
}
}
Don't worry about why I'm using a custom provider for the Endpoint instead of just:
bind(Endpoint).toInstance(new LocalEndpoint('fileystem', Protocol.File))
I'm 99.999% sure that's outside of this problem and is coded that way because of how the full (very large) code is wired.
My problem is that Guice and/or Groovy cannot find a constructor for LocalEndpoint that takes a String and Protocol argument:
1) Error in custom provider, groovy.lang.GroovyRuntimeException: Could not find matching constructor for: com.example.myapp.model.LocalEndpoint(java.lang.String, com.example.myapp.model.Protocol)
at com.example.myapp.inject.MyAppModule.providesEndpoint(MyAppModule.groovy:130)
while locating com.example.myapp.model.Endpoint
for parameter 2 at com.example.myapp.inject.MyAppModule.providesConfig(MyAppModule.groovy:98)
at com.example.myapp.inject.MyAppModule.providesConfig(MyAppModule.groovy:98)
while locating com.example.myapp.config.MyAppConfig
It then spits out a large stack trace with the following listed as the cause:
Caused by: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: com.example.myapp.model.LocalEndpoint(java.lang.String, com.example.myapp.model.Protocol)
at groovy.lang.MetaClassImpl.invokeConstructor(MetaClassImpl.java:1731)
at groovy.lang.MetaClassImpl.invokeConstructor(MetaClassImpl.java:1534)
Hopefully this is something that I can tweak by modifying Endpoint and/or LocalEndpoint, perhaps I need to pass some special parameters into the #Canonical/#TupleConstructor annotations or something. Any ideas?
I think you need to add includeSuperProperties in the TupleConstructor annotation, and that seems to resolve it, even by itself:
#TupleConstructor(includeSuperProperties=true)
So the whole thing would be:
#Canonical
abstract class Endpoint {
String name
Protocol protocol
}
#Canonical // You may not need this anymore
#TupleConstructor(includeSuperProperties=true)
class LocalEndpoint extends Endpoint {
}

Factory pattern with CDI depending on runtime parameter

I wanted to implement the factory pattern with CDI. Here we have the business case example:
A client provides a string representing a type. Depending on this type the factory returns an implementation of an interface.
I know that there are a lot of questions flying around concerning factory pattern and CDI. The difference I have here is that I resolve the implementation returned by the factory based on a runtime parameter.
I was thinking of using a producer method but then I can not think of how to inject the resolved implementation into the bean where the implementation is needed since this is a runtime parameter which is not necessarily known at contruction time.
So I thought of the pretty straight forward way of using the Instance class.
Here is the basic implementation :
// the interface. Instances of this class are returned from the factory
public interface Product {
}
// one implementation may be returned by the factory
#ProductType("default")
public class DefaultProduct implements Product {
}
// another implementation may be returned by the factory
#ProductType("myProduct")
public class MyProduct implements Product {
}
// the qualifier annotation
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.TYPE})
public #interface ProductType {
String value();
}
// the Annotation implementation to select
// the correct implementation in the factory
public class ProductTypeLiteral extends AnnotationLiteral<ProductType>
implements ProductType {
private String type;
public ProductTypeLiteral(String type) {
this.type = type;
}
#Override
public String value() {
return type;
}
}
// the factory itself. It is annotated with #Singleton because the
// factory is only needed once
#Singleton
public class Factory {
#Inject
#Any
private Instance<Product> products;
public Product getProduct(String type) {
ProductTypeLiteral literal = new ProductTypeLiteral(type);
Instance<Product> typeProducts = products.select(literal);
return typeProducts.get();
}
}
In my opinion using Instance is very sophisticated.
But this has one major drawback:
Everytime you cal the Instance.get() method you retrieve a new Instance of Product. This may be fine but the Instance instance keeps a reference of the returned instance internally. So as long as the Factory lives and each time the Instance.get() is called the more instances of Product will exist in the memory and never get garbage collected because a reference is still hold in Instance.
I thought of not making the Factory a singleton but that just shifts the problem and does not solve it. And of course it is against the factory pattern.
Another solution I tried was to iterate through the Instance instead of selecting an implementation with the help of the annotation:
#Singleton
public class Factory {
#Inject
#Any
private Instance<Product> products;
public Product getProduct(String type) {
Product product = null;
for(Product eachProduct : products) {
ProductType productType = eachProduct.getClass().
getAnnotation(ProductType.class)
if(productType.value().equals(type) {
product = eachProduct;
break;
}
}
return product;
}
}
Basically this is working. Now each time depending on the given type I retrieve the same instance of Product. That way the memory is not consumed.
But I don't like it to iterate over a collection when I have the possibility to resolve the correct implementations more elegantly.
Do you have any ideas which may solve the problem? Otherwise I may have to keep the iteration solution.
Herein lies your problem. Instance keeps reference to instances you obtain from it using get() because it is responsible for reclaiming them when they go out of scope (i.e. when the injected Instance goes out of scope. But because you made your factory a singleton, it will never go out of scope. So, make your factory a short-lived scope, like #RequestScoped or even #Dependent, that way all the returned instances will be reclaimed properly.
Maybe it can help you:
Create qualifiers:
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
public #interface MyProduct{
}
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
public #interface DefaultProduct{
}
In Factory class:
#Singleton
public class Factory {
public Product getProduct(#MyProduct MyProduct product, #DefaultProduct DefaultProduct defaultProduct) {
//What you wanna do
}
}

Servicestack registration crashes with generic types

If I have a base class for my services like
public abstract class BaseService<T,R> : ServiceStack.ServiceInterface.Service
{
public R Get(T request)
{
}
}
Then service stack crashes with
An attempt was made to load a program with an incorrect format.
I think Servicestack should ignore the abstract generic classes when registering services. Is there any way to tell servicestack to ignore some service classes ?
By default, ServiceStack is including all types in the assemblies as candidates for services. It gets that exception when it tries to instantiate the class.
By overriding the CreateServiceManager in the host class, you can inject your own filtering of types so that abstract and unclosed generics are excluded.
protected override ServiceManager CreateServiceManager(params Assembly[] assembliesWithServices)
{
return new ServiceManager(
new Container(),
new ServiceController(
() =>
assembliesWithServices.SelectMany(
assembly => assembly.GetTypes().Where(t => !t.IsAbstract && !t.IsGenericTypeDefinition))));
}

looking for a proper way to implement my generic factory

I'm struggling with implementing a factory object. Here's the context :
I've in a project a custom store. In order to read/write records, I've written this code in a POCO model/separated repository:
public class Id { /* skip for clarity*/} // My custom ID representation
public interface IId
{
Id Id { get; set; }
}
public interface IGenericRepository<T> where T : IId
{
T Get(Id objectID);
void Save(T #object);
}
public interface IContext
{
TRepository GetRepository<T, TRepository>()
where TRepository : IGenericRepository<T>
where T:IId;
IGenericRepository<T> GetRepository<T>()
where T:IId;
}
My IContext interface defines two kind of repositories.
The former is for standard objects with only get/save methods, the later allows me to define specifics methods for specific kind of objects. For example :
public interface IWebServiceLogRepository : IGenericRepository<WebServiceLog>
{
ICollection<WebServiceLog> GetOpenLogs(Id objectID);
}
And it the consuming code I can do one of this :
MyContext.GetRepository<Customer>().Get(myID); --> standard get
MyContext.GetRepository<WebServiceLog, IWebServiceLogRepository>().GetOpenLogs(myID); --> specific operation
Because most of objects repository are limited to get and save operations, I've written a generic repository :
public class BaseRepository<T> : IGenericRepository<T>
where T : IId, new()
{
public virtual T Get(Id objectID){ /* provider specific */ }
public void Save(T #object) { /* provider specific */ }
}
and, for custom ones, I simply inherits the base repository :
internal class WebServiceLogRepository: BaseRepository<WebServiceLog>, IWebServiceLogRepository
{
public ICollection<WebServiceLog> GetByOpenLogsByRecordID(Id objectID)
{
/* provider specific */
}
}
Everything above is ok (at least I think it's ok). I'm now struggling to implement the MyContext class. I'm using MEF in my project for other purposes. But because MEF doesn't support (yet) generic exports, I did not find a way to reach my goal.
My context class is looking like by now :
[Export(typeof(IContext))]
public class UpdateContext : IContext
{
private System.Collections.Generic.Dictionary<Type, object> m_Implementations;
public UpdateContext()
{
m_Implementations = new System.Collections.Generic.Dictionary<Type, object>();
}
public TRepository GetRepository<T, TRepository>()
where T : IId
where TRepository : IGenericRepository<T>
{
var tType = typeof(T);
if (!m_Implementations.ContainsKey(tType))
{
/* this code is neither working nor elegant for me */
var resultType = AppDomain.CurrentDomain.GetAssemblies().SelectMany(
(a) => a.GetTypes()
).Where((t)=>t.GetInterfaces().Contains(typeof(TRepository))).Single();
var result = (TRepository)resultType.InvokeMember("new", System.Reflection.BindingFlags.CreateInstance, null, null, new object[] { this });
m_Implementations.Add(tType, result);
}
return (TRepository)m_Implementations[tType];
}
public IGenericRepository<T> GetRepository<T>() where T : IId
{
return GetRepository<T, IGenericRepository<T>>();
}
}
I'd appreciate a bit of help to unpuzzle my mind with this quite common scenario
Not sure if I've understood you correctly, but I think you're perhaps over complicating things. To begin with, make sure you've designed your code independent of any factory or Dependency Injection framework or composition framework.
For starters lets look at what you want your calling code to look like, this is what you said:
MyContext.GetRepository<Customer>().Get(myID); --> standard get
MyContext.GetRepository<WebServiceLog, IWebServiceLogRepository>().GetOpenLogs(myID);
You don't have to agree with my naming choices below, but it indicates what I undertand from your code, you can tell me if I'm wrong. Now, I feel like the calling would be simpler like this:
RepositoryFactory.New<IRepository<Customer>>().Get(myId);
RepositoryFactory.New<IWebServiceLogRepository>().GetOpenLogs(myId);
Line 1:
Because the type here is IRepository it's clear what the return type is, and what the T type is for the base IRepository.
Line 2:
The return type here from the factory is IWebServiceLogRepository. Here you don'y need to specify the entity type, your interface logically already implements IRepository. There's no need to specify this again.
So your interface for these would look like this:
public interface IRepository<T>
{
T Get(object Id);
T Save(T object);
}
public interface IWebServiceLogRepository: IRepository<WebServiceLog>
{
List<WebServiceLog> GetOpenLogs(object Id);
}
Now I think the implementations and factory code for this would be simpler as the factory only has to know about a single type. On line 1 the type is IRepository, and in line 2, IWebServiceLogRepository.
Try that, and try rewriting your code to simply find classes that implement those types and instantiating them.
Lastly, in terms of MEF, you could carry on using that, but Castle Windsor would really make things much simpler for you, as it lets you concentrate on your architecture and code design, and its very very simple to use. You only ever reference Castle in your app startup code. The rest of your code is simply designed using the Dependency Injection pattern, which is framework agnostic.
If some of this isn't clear, let me know if you'd like me to update this answer with the implementation code of your repositories too.
UPDATE
and here's the code which resolves the implementations. You were making it a bit harder for yourself by not using the Activator class.
If you use Activator and use only one Generic parameter as I've done in the method below, you should be ok. Note the code's a bit rough but you get the idea:
public static T GetThing<T>()
{
List<Type> assemblyTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes()).ToList();
Type interfaceType = typeof(T);
if(interfaceType.IsGenericType)
{
var gens = interfaceType.GetGenericArguments();
List<Type> narrowed = assemblyTypes.Where(p => p.IsGenericType && !p.IsInterface).ToList();
var implementations = new List<Type>();
narrowed.ForEach(t=>
{
try
{
var imp = t.MakeGenericType(gens);
if(interfaceType.IsAssignableFrom(imp))
{
implementations.Add(imp);
}
}catch
{
}
});
return (T)Activator.CreateInstance(implementations.First());
}
else
{
List<Type> implementations = assemblyTypes.Where(p => interfaceType.IsAssignableFrom(p) && !p.IsInterface).ToList();
return (T)Activator.CreateInstance(implementations.First());
}
}

Resources