autofac Register closed subclasses of abstract open generic - autofac

public class Sub1 : Base<SomeClass>
{
// for sake of getting injection to work, not injecting anything in ctor
public Sub1() {}
....
}
public class Sub2 : Base<SomeOtherClass>
{
// for sake of getting injection to work, not injecting anything in ctor
public Sub2() {}
....
}
public abstract class Base<T>
{
// abstract, so no ctor
....
}
I tried the following but I'm getting the exception listed below. Notice it the exception references the Base abstract class. What am I missing?
builder.RegisterAssemblyTypes(typeof(Base<>).Assembly)
.Where(t => t.IsSubclassOf(typeof(Base<>))).AsClosedTypesOf(typeof(Base<>)).InstancePerDependency();
No constructors on type 'Base`1[SomeClass]' can be found with the constructor finder 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'.

I think you mixed with generic and non generic abstract class registrations.
You have generic abstract class. Therefore your register should be like this:
builder.RegisterAssemblyTypes(typeof(Base<>).Assembly).AsClosedTypesOf(typeof(Base<>)).InstancePerDependency();

Related

EF Core: ignore base class on table inheritance

I'm trying to use the Fluent API to use the TPH for mapping an existing class hierarchy into a single table. In this case, I've got a base class (holds common properties) and then 2 concrete classes that extend the base class with its own properties:
class Base
{
// properties
}
class A: Base {}
class B: Base {}
I'm trying to map the classes to the tables by using a custom type configurator and I thought that I could do it like this:
class BaseConfigurator: IEntityTypeConfiguration<Base>
{
public void Configure(EntityTypeBuilder<Base> builder)
{
builder.ToTable("...");
// more mappings
builder.HasDescriminator(e => e.Type)
.HasValue<A>("A")
.HasValue<B>("B");
}
}
When I try to run the code, I get an error message which says that the base type is part of the hierarchy, but does not have a discriminator value configured.
Since the base type is abstract and it's there only to be save the common properties, how can I say that the base type should be ignored?
Thanks.
Just noticed that I'm missing the abstract qualifier from the base class declaration...adding it seems to solve the problem.

Why #ContributesAndroidInjector doesn't provide Android Framework type

I have simplified my application to get the root of the problem and here is the simplified version. I'm implementing Dagger 2 using following configuration:
AppComponent
#Component(modules = [
AndroidSupportInjectionModule::class,
ActivityBindingModule::class
])
interface AppComponent: AndroidInjector<MyApp> {
#Component.Builder
interface Builder{
#BindsInstance
fun application(application: Application): Builder
fun build(): AppComponent
}
}
ActivityBindingModule
#Module
abstract class ActivityBindingModule {
#ContributesAndroidInjector
abstract fun mainActivity(): MainActivity
#Module
companion object{
#JvmStatic
#Provides
fun provideString(mainActivity: MainActivity): String{
return "Tent"
}
}
}
MainActivity
class MainActivity : DaggerAppCompatActivity() {
#Inject
lateinit var string: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
println("meco simplest ${string}")
}
}
When I run the application I get the following error. What I don't understand is ContributesAndroidInjector is already providing an instace of MainActivity why Dagger still complains about it.
MainActivity cannot be provided without an #Inject constructor or an
#Provides-annotated method
EDIT for #yavor
Keep all classes as is and separate ActivityBindingModule implementation into two classes. Now you can see that instance of the MainActivity is provided and Dagger is not complaining about it.
ActivityBindingModule
#Module
abstract class ActivityBindingModule {
#ContributesAndroidInjector(modulese [StringProviderModule::class])
abstract fun mainActivity(): MainActivity
}
StringProviderModule
#Module
class StringProviderModule {
#Module
companion object{
#JvmStatic
#Provides
fun provideString(mainActivity: MainActivity): String{
return "Tent"
}
}
}
What I don't understand is ContributesAndroidInjector is already providing an instace of MainActivity why Dagger still complains about it.
ContributesAndroidInjector in docs says:
Generates an {#link AndroidInjector} for the return type of this method. The injector is implemented with a {#link dagger.Subcomponent} and will be a child of the {#link dagger.Module}'s component.
So it does not provide MainActivity.
Why do you need it actually at all? I see that you are passing it as parameter to the function:
fun provideString(mainActivity: MainActivity)
but do you really need it there? In general you should inject dependencies in MainActivity. MainActivity should use them. If both(MainActivity and the string) they know about each other it is first - not a good design, and second: you are close to create cyclic dependencies which Dagger 2 does not support and throws exception.
You probably forgot to inject your application in MyApp. You should have something like this (you might need to modify it a bit to fit your AppComponent:
DaggerAppComponent.builder()
.application(this)
.build()
.inject(this)
Also, Dagger is actually providing your MainActivity through your #ContributesAndroidInjector annotated method but that's not what you're injecting.
You're injecting a string so Dagger is using your provideString method. Since this method requires a MainActivity instance to work, Dagger is looking for such a method annotated with #Provides. You don't have any and Dagger won't look at your #ContributesAndroidInjector method since it does not have any reasons to do so.
If you want it to work, you actually have to define your provideString method in a separate module and install it inside your #ContributesAndroidInjector:
#Module
abstract class ActivityBindingModule {
#ContributesAndroidInjector(modules = [StringModule::class])
abstract fun mainActivity(): MainActivity
}
#Module
class StringModule {
#JvmStatic
#Provides
fun provideString(mainActivity: MainActivity): String = "Hehe"
}

Why we cannot mark the visibility of a class as "protected" in kotlin?

I am new to kotlin I have been learning about inheritance in kotlin recently, and then I realised that we cannot mark the visibility of a class as "protected". Correct me if i am wrong, or is there any other way to make a class protected ?
You can mark protected only parts of classes, so that they become accessible only from the derived classes. You can mark protected a member property, a member function or a nested class:
open class X {
protected val v: SomeType = someValue
protected fun f() { }
protected class Y { ... }
}
But you cannot mark protected anything that does not belong to a class (e.g. a top-level class or function), because the modifier would make no sense: a top-level entity is not subject to inheritance, thus there can be no derived class that would access it.

How to solve "Implementation restriction: trait ... accesses protected method ... inside a concrete trait method."

A Java library class I'm using declares
protected getPage(): Page { ... }
Now I want to make a helper Scala mixin to add features that I often use. I don't want to extend the class, because the Java class has different subclasses I want to extend at different places. The problem is that if I use getPage() in my mixin trait, I get this error:
Implementation restriction: trait MyMixin accesses protected method getPage inside a concrete trait method.
Is there a solution how to make it work, without affecting my subclasses? And why is there this restriction?
So far, I came up with a work-around: I override the method in the trait as
override def getPage(): Page = super.getPage();
This seems to work, but I'm not completely satisfied. Luckily I don't need to override getPage() in my subclasses, but if I needed, I'd get two overrides of the same method and this work-around won't work.
The problem is that even though the trait extends the Java class, the implementation is not actually in something that extends the Java class. Consider
class A { def f = "foo" }
trait T extends A { def g = f + "bar" }
class B extends T { def h = g + "baz" }
In the actual bytecode for B we see
public java.lang.String g();
Code:
0: aload_0
1: invokestatic #17; //Method T$class.g:(LT;)Ljava/lang/String;
4: areturn
which means it just forwards to something called T$class, which it turns out is
public abstract class T$class extends java.lang.Object{
public static java.lang.String g(T);
Code:
...
So the body of the code isn't called from a subclass of A at all.
Now, with Scala that's no problem because it just omits the protected flag from bytecode. But Java enforces that only subclasses can call protected methods.
And thus you have the problem, and the message.
You cannot easily get around this problem, though the error message suggests what is perhaps the best alternative:
public class JavaProtected {
protected int getInt() { return 5; }
}
scala> trait T extends JavaProtected { def i = getInt }
<console>:8: error: Implementation restriction: trait T accesses
protected method getInt inside a concrete trait method.
Add an accessor in a class extending class JavaProtected as a workaround.
Note the last line.
class WithAccessor extends JavaProtected { protected def myAccessor = getInt }
trait T extends WithAccessor { def i = myAccessor }
works.

Private and protected constructor in Scala

I've been curious about the impact of not having an explicit primary constructor in Scala, just the contents of the class body.
In particular, I suspect that the private or protected constructor pattern, that is, controlling construction through the companion object or another class or object's methods might not have an obvious implementation.
Am I wrong? If so, how is it done?
You can declare the default constructor as private/protected by inserting the appropriate keyword between the class name and the parameter list, like this:
class Foo private () {
/* class body goes here... */
}
Aleksander's answer is correct, but Programming in Scala offers an additional alternative:
sealed trait Foo {
// interface
}
object Foo {
def apply(...): Foo = // public constructor
private class FooImpl(...) extends Foo { ... } // real class
}