kapt error while processing dagger2 code - dagger-2

In ClientModule.kt
#Singleton
#Provides
fun provideClient(application: Application, configuration: OkhttpConfiguration?,
sslConfiguration: SSLConfiguration?, cookieJarConfiguration: CookieJarConfiguration?, builder: OkHttpClient.Builder, intercept: Interceptor,
interceptors: List<Interceptor>?, handler: GlobalHttpHandler?): OkHttpClient{...}
In AppModule.kt
#Singleton
#Provides
fun provideInterceptors(): List<Interceptor>? {
return mInterceptors
}
The error msg is:
e: /Users/xiaoqidong/AndroidStudioProjects/DemoKotlin/framework/build/tmp/kapt3/stubs/debug/com/bnpparibas/framework/di/component/AppComponent.java:23: error: java.util.List<? extends okhttp3.Interceptor> cannot be provided without an #Provides-annotated method.
public abstract okhttp3.OkHttpClient okHttpClient();
^
java.util.List<? extends okhttp3.Interceptor> is injected at
com.bnpparibas.framework.di.module.ClientModule.provideClient(…, interceptors, …)
okhttp3.OkHttpClient is provided at
com.bnpparibas.framework.di.component.AppComponent.okHttpClient()
It's so weird that the generated java file changed my function signature from List< Interceptor> to List
The following is the generated file:
#Override
public OkHttpClient get() {
return Preconditions.checkNotNull(
module.provideClient(
applicationProvider.get(),
configurationProvider.get(),
sslConfigurationProvider.get(),
cookieJarConfigurationProvider.get(),
builderProvider.get(),
interceptProvider.get(),
interceptorsProvider.get(),
handlerProvider.get()),
"Cannot return null from a non-#Nullable #Provides method");
}
public static Factory<OkHttpClient> create(
ClientModule module,
Provider<Application> applicationProvider,
Provider<ClientModule.OkhttpConfiguration> configurationProvider,
Provider<ClientModule.SSLConfiguration> sslConfigurationProvider,
Provider<ClientModule.CookieJarConfiguration> cookieJarConfigurationProvider,
Provider<OkHttpClient.Builder> builderProvider,
Provider<Interceptor> interceptProvider,
Provider<List<? extends Interceptor>> interceptorsProvider,
Provider<GlobalHttpHandler> handlerProvider) {
return new ClientModule_ProvideClientFactory(
module,
applicationProvider,
configurationProvider,
sslConfigurationProvider,
cookieJarConfigurationProvider,
builderProvider,
interceptProvider,
interceptorsProvider,
handlerProvider);
}
}
How can stop the kapt change my function signature ?

Related

Replacing WebAuthenticationDetails with Webflux code

I am working on Spring boot 3 and want to convert non-reactive code to reactive code.
In non-reactive code, I use a class which extends WebAuthenticationDetails.
It needs to call default constructor with HttpServletRequest as parameter.
Now, as I want to move to Webflux[Reactive code]. I am removing "extends WebAuthenticationDetails".
And replacing HttpServletRequest with ServerWebExcahnge.
Is this approach correct?
Sample code:
Non-reactive Code:
import org.springframework.security.Authentication.AuthenticationDetailsSource;
class AuthSource implements AuthenticationDetailsSource<HttpServletRequest, Auth>{
#Override
public Auth buildDetails(HttpServletRequest req){
return new Auth(req);
}
}
class Auth extends WebAuthenticationDetails{
Auth(HttpServletRequest req){
super(req);
}
}
Reactive code:
import org.springframework.security.Authentication.AuthenticationDetailsSource;
class AuthReactiveSource implements AuthenticationDetailsSource<ServerWebExchange, AuthReactive>{
#Override
public AuthReactive buildDetails(ServerWebExchange req){
return new AuthReactive(req);
}
}
class AuthReactive{ // Not extending any class
AuthReactive(ServerWebExchange req){
}
}
Just to understand , Is this correct?

Java code fails in Intellij but not in eclipse, with ambiguous method error

I have the below Java class (with nested classes/interfaces). When running the main method from within Eclipse (Version: 2019-09 R (4.13.0)) I get the following output:
java.version: 1.8.0_241
PageA.m3() called
This is the command line used by Eclipse:
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/bin/java -agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:52180 -javaagent:/Users/*****/eclipse/java-2019-09/Eclipse.app/Contents/Eclipse/configuration/org.eclipse.osgi/222/0/.cp/lib/javaagent-shaded.jar -Dfile.encoding=UTF-8 -classpath <a-list-of-.jar-files> _play.PageTest
When running the same code from within Intellij (IDEA 2019.3.3 (Community Edition)) I get the following output:
src/main/java/_play/PageTest.java:13: error: reference to m1 is ambiguous
.m1(pageAorB -> ((SpecialPage<?>) pageAorB).m3());
^
both method m1(Consumer<T#1>) in Page and method m1(Consumer<T#2>) in AbstractPage match
where T#1,T#2 are type-variables:
T#1 extends Page<T#1> declared in interface Page
T#2 extends Page<T#2> declared in class AbstractPage
Why do I get this error in Intellij but not in Eclipse? Is there a way to solve this so it runs without error in Intellij?
Here is the Java class:
package _play;
import java.util.function.Consumer;
import java.util.function.Function;
public class PageTest {
public static void main(String[] args) {
System.out.println("java.version: " + System.getProperty("java.version"));
new PageC()
.m2(pageC -> (1 == 1 ? new PageA() : new PageB()))
.m1(pageAorB -> ((SpecialPage<?>) pageAorB).m3());
}
public static interface Page<T extends Page<T>> {
T m1(Consumer<T> c);
<R> R m2(Function<? super T, ? extends R> f);
}
public static abstract class AbstractPage<T extends Page<T>> implements Page<T>{
#Override
public T m1(Consumer<T> c){
c.accept(self());
return self();
}
#Override
public final <R> R m2(Function<? super T, ? extends R> f) {
return f.apply(self());
}
abstract protected T self();
}
public static interface SpecialPage<T extends Page<T>> extends Page<T> {
T m3();
}
public static class PageC extends AbstractPage<PageC> {
#Override
protected PageC self() {
return this;
}
}
public static class PageB extends AbstractPage<PageB> implements SpecialPage<PageB> {
#Override
public PageB m3() {
System.out.println("PageB.m3() called");
return this;
}
#Override
public PageB self() {
return this;
}
}
public static class PageA extends AbstractPage<PageA> implements SpecialPage<PageA> {
#Override
public PageA m3() {
System.out.println("PageA.m3() called");
return this;
}
#Override
public PageA self() {
return this;
}
}
}
EDIT
In this case the Page interface and AbstractPage class are in a library that the client can't change. but the client should be able to extend the Page interface.
The question is, is the Eclipse compiler (ecj) of version 4.13 or javac 1.8.0_241 which is used by IntelliJ and Gradle by default right?
The error message of javac says it's ambiguous because in AbstractPage the type variable T refers to the type variable of AbstractPage (named T) and also refers to the different type variable of Page (also named T). But in fact, both type variable refer to the same type, not because they are named the same, but because AbstractPage implements Page<T>. It is not ambiguous and javac erroneously gives the compile error here.
As a workaround of this javac bug you can do one of the following:
Use the Eclipse compiler also in IntelliJ and Gradle
Rewrite the code in the main method using a variable of SpecialPage<? extends Page<?>> for the intermediate result so that javac need not infer it:
SpecialPage<? extends Page<?>> pageAorB = new PageC().m2(pageC -> (1 == 1 ? new PageA() : new PageB()));
pageAorB.m1(specialPage -> ((SpecialPage<?>) specialPage).m3());

Mock an Interface with Mockito return a NullPointerException

I m trying create unit tests for one project.I m facing a problem because when I try control the result of an interface(mock). When the code get the Interface variable that return a NullPointerException.
Firstly I tried #Override the method in my test class (ClassA), but it don't work. After that I tried mock the interface object and control the comportment with Mockito.When().tehnReturn();
I will put here my code, I read some solutions but none works.
My Interface:
#FunctionalInterface
public interface Interface {
UpdateXResponse process(UpdateXRequest request) throws Exception;
}
The class I want to test:
#Service(ClassA.class)
public class ClassA extends VService implements UpdateX {
#Reference
#Inject
private Interface interface;
#Inject
public ClassA(...) {...}
#Override
public UpdateXResponse process(UpdateXRequest request) throws Exception {
UpdateXResponse response = initResponse(context, request, new UpdateXResponse());
UpdateXInput input = request.getInput();
UpdateXOutput output = new UpdateXOutput();
response.setOutput(output);
try {
firstMethodCall(...);
} catch (Exception t) {
throwCorrectException(t, logger);
}
return response;
}
private void firstMethodCall(...) throws Exception {
TypeF typeF = callInterfaceMethod(...);
...
}
/**
* Orchestrates Interface service
*/
protected TypeF callInterfaceMethod(...) {
...
request.setInput(input);
request.setHeader(header);
InterfaceResponse response = interface.process(request); // LINE ERROR - In this step interface is NULL when the test get this
return response;
}
}
And finally my class test:
#RunWith(PowerMockRunner.class)
#PrepareForTest(value = {ClassA.class,Interface.class} )
public class WithPowerMockUnitTest{
#InjectMocks
private ClassA classA;
private Interface interface;
#Before
public void setUp() throws Exception {
InterfaceRequest InterfaceRequest = createInterfaceRequest();
InterfaceResponse serviceUnavailableResponse = createInterfaceResponse();
Interface = Mockito.mock(Interface.class);
when(Interface.process(Mockito.any(InterfaceRequest.class))).thenReturn(serviceUnavailableResponse);
}
#Test
public void testh() throws SOAException {
InterfaceResponse res = interface.process(Mockito.any(InterfaceRequest.class)); // There all run ok. The interface is not null and return what i expected.
System.out.println("RES "+res);
}
#Test
public void test() {
assertNotNull(classA); // not null
assertNotNull(interface); // not null
}
#Test
public void newTest() throws Exception {
InterfaceRequest InterfaceRequest = createInterfaceRequest();
InterfaceResponse serviceUnavailableResponse = createInterfaceResponse();
UpdateXResponse response = ClassA.process(updateXRequest()); // PROBLEM!! When that get the LINE ERROR the interface is null! WHY?
}
}
I put some comments in the lines where the problem exists for me.
public interface A{
Response process(Request r) throws Exception;
}
public class B{
private Class_That_Override_Interface_method ctoim;
public Response function(){
X res = method_B();
}
protected X method_B(){
response res = ctoim.process(request); // That ctoim is always NULL when the test get that line/call
}
}
Thanks
You're missing the #Mock annotation on your Interface variable.
Therefore the mock is not injected into your classA and the newTest() fails. (In this case remove Interface = Mockito.mock(Interface.class); from the setUp method).
Alternativly remove the #InjectMocks annotation and create your class under test manually passing your mock into the constructor.
For this specific case (assuming its a different case from the last question)
there doesn't seem to be a need to involve PowerMockito. So unless you left out some relevant parts you might as well just use the MockitoJUnitRunner.
Ps.:
Also remeber what I said last time about compilable examples?
interface is a keyword and can't be used for variables.
You should also aim to write variables identical all the times (not Interface and interface / classA and ClassA)
And in case you haven't read it yet check out the help section about minmal reproducible examples.
Edit:
I fogot to mention that the line interface.process(Mockito.any(InterfaceRequest.class)); in testh() is actually invalid syntax. You should use ArgumentMatchers only for parameters of mocked methods.
Also consider adding the MockitoAnnotations.initMocks(this); to your setUp method, when using the PowerMockRunner.

Dagger can not inject ViewModel with KClass

I am moving my project java to kotlin, but got some confusion about KClass and Class
Here is my BaseActivity
abstract class BaseActivity<DB : ViewDataBinding, VM : BaseViewModel> : DaggerAppCompatActivity() {
private lateinit var mCustomDialog: CustomDialog
private lateinit var mViewDataBinding: DB
private lateinit var mViewModel : VM
#Inject
lateinit var viewModelFactory: ViewModelFactory
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Set Custom Dialog
mCustomDialog = CustomDialog(this, R.style.LoadingDialogStyle)
// Set ViewModel
mViewModel = ViewModelProviders.of(this, viewModelFactory).get(getViewModelClass().java)
// Set DataBinding
mViewDataBinding = DataBindingUtil.setContentView(this, getLayoutId())
mViewDataBinding.lifecycleOwner = this
mViewDataBinding.setVariable(getBindingVariable(), mViewModel)
mViewDataBinding.executePendingBindings()
// Initialize UI
prepareView(savedInstanceState)
}
#LayoutRes
abstract fun getLayoutId(): Int
protected abstract fun getViewModelClass(): KClass<VM>
abstract fun getBindingVariable(): Int
fun getViewModel(): VM {
return mViewModel
}
fun getViewDataBinding() : DB {
return mViewDataBinding
}
I am using protected abstract fun getViewModelClass(): KClass<VM> function for initializing ViewModel class in the function below
ViewModelProviders.of(this, viewModelFactory).get(getViewModelClass().java)
I use ViewModel in activities by this way
class SplashActivity : BaseActivity<ActivitySplashBinding, SplashViewModel>() {
override fun getViewModelClass(): KClass<SplashViewModel> {
return SplashViewModel::class
}
override fun getLayoutId(): Int {
return R.layout.activity_splash
}
override fun getBindingVariable(): Int {
return BR.vm
}
override fun prepareView(savedInstanceState: Bundle?) {
getViewModel().testLog()
}
}
But when I run the project, I got this error
error: [Dagger/MissingBinding] java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> cannot be provided without an #Provides-annotated method.
public abstract interface AppComponent extends dagger.android.AndroidInjector<com.example.example.MyApp> {
^
java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is injected at
com.example.example.utils.ViewModelFactory(viewModels)
com.example.example.utils.ViewModelFactory is injected at
com.example.example.base.BaseActivity.viewModelFactory
com.example.example.ui.splash.SplashActivity is injected at
dagger.android.AndroidInjector.inject(T) [com.example.example.di.AppComponent ? com.example.example.di.ActivityBindingsModule_SplashActivityInjector$app_debug.SplashActivitySubcomponent]
So I made some research and find out it is about KClass in my ViewModelKey
Here is ViewModelKey
#Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
#Retention(AnnotationRetention.RUNTIME)
#MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)
If I do not change my code to Kotlin and use old Java class like this it works properly
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#MapKey
public #interface ViewModelKey {
Class<? extends ViewModel> value();
}
This is my ViewModelFactory class
#Suppress("UNCHECKED_CAST")
class ViewModelFactory #Inject
constructor(private val viewModels: MutableMap<Class<out ViewModel>, #JvmSuppressWildcards Provider<ViewModel>>) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
val creator = viewModels[modelClass]
?: viewModels.asIterable().firstOrNull { modelClass.isAssignableFrom(it.key) }?.value
?: throw IllegalArgumentException("unknown model class $modelClass")
return try {
creator.get() as T
} catch (e: Exception) {
throw RuntimeException(e)
}
}
}
My SplashActivityModule
#Module
abstract class SplashActivityModule {
#Binds
#IntoMap
#ViewModelKey(SplashViewModel::class)
internal abstract fun provideSplashViewModel(splashViewModel: SplashViewModel) : ViewModel
}
So how can I use ViewModelKey properly with Kotlin and what is main cause of this error, any help will be appreciated
Your ViewModelKey be like
#MustBeDocumented
#kotlin.annotation.Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
#kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
#MapKey
internal annotation class ViewModelKey(val value: KClass<out ViewModel>)
As mentioned this question problem is related to Kotlin version. Using higher than 1.3.30 version solves the problem.

Dagger2 Circular Dependency Error

I am using dagger2 2.16 version for dependency injection inside mine android project. I examine a lot of examples, and although I do not have a similar approach I get the error of "circular dependency".
Mine source code;
AppComponent.kt
#Singleton
#Component(
modules = [
AndroidSupportInjectionModule::class,
AppModule::class,
ActivityBuilderModule::class]
)
interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
fun application(application: Application): Builder
fun build(): AppComponent
}
fun inject(app: App)
}
App.kt
class App : Application(), HasActivityInjector {
#Inject
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>
override fun onCreate() {
super.onCreate()
AppInjector.init(this)
initOneSignal()
}
private fun initOneSignal() = OneSignal.startInit(this).setNotificationOpenedHandler(CustomNotificationOpenedHandler()).inFocusDisplaying(OneSignal.OSInFocusDisplayOption.Notification).init()
override fun activityInjector() = dispatchingAndroidInjector
}
ActivityBuilderModule.kt
#Module
abstract class ActivityBuilderModule {
#ContributesAndroidInjector
abstract fun contributeSplashActivity(): SplashActivity
}
AppModule.kt
#Module(includes = [(ViewModelModule::class)])
class AppModule {
#Singleton
#Provides
fun provideContext(app: Application): Context = app.applicationContext;
#Singleton
#Provides
fun provideApiService(client: OkHttpClient): ApiService {
return Retrofit.Builder()
.baseUrl(Constants.baseUrl)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
.create(ApiService::class.java)
}
#Singleton
#Provides
fun provideOkHttpClient(interceptor: HttpLoggingInterceptor): OkHttpClient {
return OkHttpClient.Builder().addInterceptor(interceptor).build()
}
#Singleton
#Provides
fun provideHttpLoggingInterceptor(): HttpLoggingInterceptor {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
return interceptor
}
}
If I remove the ActivityBuilderModule from the AppComponent, the project is compiled without problems. But if you add to the modules section, the project gives the error below.
error: [ComponentProcessor:MiscError]
dagger.internal.codegen.ComponentProcessor was unable to process this
interface because not all of its dependencies could be resolved. Check
for compilation errors or a circular dependency with generated code.
Please help me.
In App.kt you need to initialize component with the application context. the line
AppInjector.init(this)
should be inside the Activity i.e. splashActivity in which you're going to inject the dependencies.
The above mentioned error message might also appear, because kotlin stdlib is not declared as dependency. So adding e.g. implementation("org.jetbrains.kotlin:kotlin-stdlib:1.3.60") in your build.gradle(.kts) file might also help.