Dagger: Inject named string in constructor - properties

I have a properties file and I would like to inject a property in a service.
I would like use the constructor method for DI like this:
#Inject
public ScanService(#Named("stocks.codes") String codes, IYahooService yahooService) {
this.yahooService = yahooService;
this.codes = codes;
}
I try to do a module like specified in this link => Dagger: Inject #Named strings?
#Provides
#Named("stocks.code")
public String providesStocksCode() {
return "test";
}
And for the provider method for my service:
#Provides
#Singleton
public IScanService provideScanService(String codes, IYahooService yahooService){
return new ScanService(codes, yahooService);
}
When I run the compilation I get this error:
[ERROR]
/Users/stocks/src/main/java/net/modules/TestModule.java:[22,7]
error: No injectable members on java.lang.String. Do you want to add
an injectable constructor? required by
provideScanService(java.lang.String,net.IYahooService)
for net.modules.TestModule
How can I inject my property correctly in the constructor ?
Thanks.

You have two different names: stocks.codes and stocks.code.
You will also have to annotate your provideScanService codes parameter:
#Provides
#Singleton
public IScanService provideScanService(#Named("stocks.codes") String codes, IYahooService yahooService){
return new ScanService(codes, yahooService);
}
Or do it like this:
#Provides
#Singleton
public IScanService provideScanService(ScanService scanService){
return scanService;
}

If you mean Dagger 2, I can help you.
First you have to declare dependencies in Component
#Singleton
#Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
void inject(BaseActivity baseActivity);
#Named("cloud") UserDataSource userCloudSource();
#Named("disc") UserDataSource userDiscSource();
UserDataRepository userDataRepository();
}
then instantiate it in Module
#Module
public class ApplicationModule {
#Provides #Named("cloud")
UserDataSource provideCloudUserSource(UserCloudSource userSource) {
return userSource;
}
#Provides #Named("disc")
UserDataSource provideDiscUserSource(UserDiscSource userSource) {
return userSource;
}
#Provides
UserDataRepository provideUserRepository(UserDataRepository repository) {
return repository;
}
}
then inject it in constructor with #Named qualifiers
#Inject
public UserDataRepository(#Named("cloud") UserDataSource cloudSource,
#Named("disc") UserDataSource discSource) {
this.cloudDataSource= cloudSource;
this.discDataSource = discSource;
}

Related

in kotlin, how to access protected static member in parent class from sub class

It is code worked in java but after convert to kotlin it does not compile.
Having a base class which has some defines as static protected member in the companion object:
abstract class ParentClass {
companion object {
#JvmField
final protected val SERVICE_TYPE_A = "the_service_type_a"
}
}
and the child class:
class ChildClass: ParentClass {
public override fun getServiceType(): String {
return SERVICE_TYPE_A. //<== got compile error
}
}
it does not compile.
how to access a parent class static protected member from subclass?
You need to use #JvmStatic instead as follows:
abstract class ParentClass {
companion object {
#JvmStatic
protected val SERVICE_TYPE_A = "the_service_type_a"
}
abstract fun getServiceType(): String
}
The final keyword in SERVICE_TYPE_A is redundant since everything is final by default in Kotlin. This also mean that if you want ParentClass to be extended, then you need to explicitly define it as open.
Then your ChildClass would look as follows:
class ChildClass: ParentClass() {
override fun getServiceType(): String {
return SERVICE_TYPE_A
}
}

Dagger #Provides in Kotlin

I'm trying to understand Dagger. I created applicationInjector class :
class BaseApplication : DaggerApplication() {
override fun applicationInjector(): AndroidInjector<out DaggerApplication>? {
return DaggerAppComponent.builder().application(this)?.build()
}
}
And here's my AppComponent
#Component(
modules = [AndroidSupportInjectionModule::class,
ActivityBuilderModules::class]
)
interface AppComponent : AndroidInjector<BaseApplication> {
#Component.Builder
interface Builder {
#BindsInstance
fun application(application: Application?): Builder?
fun build(): AppComponent?
}
}
Now what I want to do is to to inject simple String to Activity (really basic, right ?)
In Java it works like this :
#Module
abstract class ActivityBuilderModules {
#ContributesAndroidInjector
abstract fun contributeAuthActivity() : AuthActivity
//JAVA
#Provides
public static String provideTestString() {
return "TEST "
}
however we don't have static function in Kotlin, right ? And it needs to be static cause I'm getting an error :
error: com.example.kotlintests.di.ActivityBuilderModules is abstract and has instance #Provides methods. Consider making the methods static or including a non-abstract subclass of the module instead.
public abstract interface AppComponent extends dagger.android.AndroidInjector<com.example.kotlintests.BaseApplication> {
I tried with package level function but it didn't work. How can I add provideTestString function in Kotlin ?

How to get reference to static class of Java super class in Kotlin

I've got sample third party Java code:
public class ApiClass extends PackagePrivateClass {
}
abstract class PackagePrivateClass {
public static class StaticClass {
}
}
So only ApiClass and StaticClass are public. In Java I can get reference to StaticClass with: ApiClass.StaticClass. For the same code in Kotlin I got Unresolved reference: StaticClass. I can't also get reference via PackagePrivateClass, because it's package private (captain obvious). Is there any hack to get reference to StaticClass (it's third party code so I can't simply make PackagePrivateClass public)?
I understand that it's probably 'by design', however it forbids me from using 3p code
It seems the only solution is to build Java wrapper class that your kotlin class can access to.
public class ApiClass extends PackagePrivateClass {
}
abstract class PackagePrivateClass {
public static class StaticClass {
void instanceFunction() {
}
static void classFunction() {
}
}
}
The adapter java class (StaticClassAdapter.java):
class StaticClassAdapter {
private static ApiClass.StaticClass staticClass;
void instanceFunction() {
staticClass.instanceFunction();
}
static void classFunction() {
PackagePrivateClass.StaticClass.classFunction();
}
}
So in your kotlin code...
class KotlinClass {
fun main() {
StaticClassAdapter().instanceFunction()
StaticClassAdapter.classFunction()
}
}

Dagger 2 public field injection produces 'private field injection' error

I'm trying to set up a very basic field injection using Dagger2 with the following structure:
class ToInject {}
class Injected {
#Inject
var toInject: ToInject? = null
}
#Module
object BaseModule {
var toInject: ToInject? = null
#Provides
#JvmStatic
fun toInjectProvider(): ToInject {
if (toInject == null) {
toInject = ToInject()
}
return toInject as ToInject
}
}
The field I'm trying to inject is definately PUBLIC but the compiler returns the following error
Dagger does not support injection into private fields
Can anyone please explain why am I getting this error and how to fix it?
BTW constructor injection works:
class Injected #Inject constructor(var toInject: ToInject){}
Try explicitly annotating the setter method:
class Injected {
#set:Inject
var toInject: ToInject? = null
}
or
class Injected {
var toInject: ToInject? = null
#Inject set
}
You can also annotate your field as #JvmField:
class Injected {
#JvmField
#Inject
var toInject: ToInject? = null
}
The problem is how Kotlin is translated to Java.
This Kotlin class:
class Injected {
var toInject: ToInject? = null
}
actually becomes this Java class:
public final class Injected {
#Nullable
private ToInject toInject;
#Nullable
public final ToInject getToInject() {
return this.toInject;
}
public final void setToInject(#Nullable ToInject value) {
this.toInject = value;
}
}
So despite the fact you set your field public in Kotlin, under the hood it's just a private field with a public setter and getter.
I am having similar issue while injecting primitive Int value. Only adding #JvmField worked for me. Thanks #jsamol for pointing out.
#JvmField
#Inject
#Named(NAMED_APP_LOGO)
var appLogo: Int = 0

Arquillian with Mockito and CDI

Is it possible to create spy(mock) object in testing class?
Here is tested class.
#Stateless
#Slf4j
public class UserDao {
#Inject
private TestBean testBean;
public String mock() {
return testBean.mock();
}
public String notMock() {
return testBean.notMock();
}
}
TestBean code
#Stateless
#Slf4j
public class TestBean {
public String notMock() {
return "NOT MOCK";
}
public String mock() {
return "IMPLEMENTED MOCK";
}
}
Here's my test
#RunWith(Arquillian.class)
public class UserDataTest {
#Rule
public ExpectedException thrown = ExpectedException.none();
#Inject
private UserDao userDao;
#Deployment
protected static Archive createWar() {
File[] dependencies = Maven.configureResolver()
.withRemoteRepo("nexus-remote", "http://maven.wideup.net/nexus/content/groups/public/", "default")
.withRemoteRepo("nexus-release", "http://maven.wideup.net/nexus/content/repositories/releases/", "default")
.resolve(
"org.slf4j:slf4j-simple:1.7.7",
"eu.bitwalker:UserAgentUtils:1.15",
"org.mockito:mockito-all:1.10.8"
).withoutTransitivity().asFile();
return ShrinkWrap
.create(WebArchive.class, "pass.jpa.war")
.addAsWebInfResource("jbossas-ds.xml")
.addAsWebInfResource("jboss-deployment-structure.xml")
.addAsLibraries(
PassApiDeployments.createDefaultDeployment(),
PassUtilLibrary.createDefaultDeployment(),
PassJpaDeployments.createDefaultDeployment()
).addAsLibraries(dependencies);
}
#Test
public void testMock() {
assertEquals("MOCK", userDao.mock());
}
#Test
public void testNotMock() {
assertEquals("NOT MOCK", userDao.notMock());
}
}
I'd like to create a spy object on TestBean to change result on method test() of this bean.
So is it possible to create TestBean spy in UserDao.
I solve some problems through producer like this.
#Singleton
public class MockFactory {
#Produces
#ArquillianAlternative
public TestBean getTestBean() {
return when(mock(TestBean.class).mock()).thenReturn("MOCK").getMock();
}
}
But in this example I need create on Bean completely on my own. And if it is bean with additional dependencies and thus i will manage all dependencies.
As far as I know, its not possible to use a mocking framework in combination with arquillian ...
I haven't used it myself, but this Arquillian extension seems to be specifically designed to support Mockito Spy objects in an Arquillian test: https://github.com/topikachu/arquillian-extension-mockito/