How to call Kotlin class key in Java? - java

We're making Dagger module for providing class as follows, but we encounter the problem.
CustomHelper is *.kt class, if we use CustomHelper::class into #ClassKey, it won't be recognized in Java and get syntax error.
Even if we change to use CustomHelper.class as follows, we still get compile error.
#Provides
#IntoMap
#ClassKey(CustomHelper.class) // <- not work
static Helper provideCustomHelper(CustomHelper customHelper) {
return customHelper;
}
We will appreciate any help.

Check your module build.gradle. Maybe you forget to add apply plugin: 'kotlin-android' in top of build.gradle.

For using Kotlin class you need to swap it to java class using javaClass method as in
#Provides
#IntoMap
#ClassKey(javaClass<CustomHelper>()) // <- not work
static Helper provideCustomHelper(CustomHelper customHelper) {
return customHelper;
}

Related

can't figure out the java annotation processor

I'm trying to deal with annotation processors. I followed tutorials. Here is my code:
#ExampleAnnotation
private void someMethod(){
System.out.println("hi");
}
#Retention(RetentionPolicy.SOURCE)
#Target(ElementType.METHOD)
public #interface ExampleAnnotation {
}
#SupportedAnnotationTypes("org.example.ExampleAnnotation")
public class Processor extends AbstractProcessor {
#Override
public boolean process(Set<? extends TypeElement> anots, RoundEnvironment roundEnvironment) {
anots.forEach(System.out::println);
return true;
}
}
I created META-INF/SERVICES/javax.annotation.processing.Processor
and registered my processor: org.example.Processor. It seems like everything is OK, but block of code in the processor just dont start. I have no idea what is wrong. P.S.: I use Gradle and Java 11.
i fixed my issue and decided to make a little step-by-step tutorial to create simple JAP:
Java-Annotation-Processor-guide
This is guide for annotation processing using gradle
I spent 3 days trying to deal with it, but with this little tutorial you will made JAP in 5 minutes.
sorry for bad english :)
So, first you should do is create gradle subproject for your project:
create project itself with gradle init or intellij
add to your main project's settings.gradle file this line include "*your subproject name, lets say:*annotation-processor"
Congrats, now let go to the processor itself
here is so much tutorials on the web about this part, so you can read something like this https://www.baeldung.com/java-annotation-processing-builde,
or this (Если ты русский): https://habr.com/ru/company/e-legion/blog/206208/
Final step is very easy - you will add your annotation processor to main project.
!!! instead of annotation-processor you should use your subproject name !!!
kotlin (or java + kotlin) -> {
add this plugin to your plugins: id "org.jetbrains.kotlin.kapt" version "1.7.21"
add this to your dependencies:
kapt project('annotation-processor')
compileOnly project('annotation-processor')
}
java -> {
add this to your dependencies:
annotationProcessor project('annotation-processor')
compileOnly project('annotation-processor')
}
(or you can read this on github: https://github.com/Blu3cr0ss/Java-Annotation-Processor-guide)

I faced two error when I run my retrofit test with robolectric befor the test starts

I have written this test in test pakage, for test of a retrofit class, but even before test stars,in addition to unknownable "constants" in #Config, this error is shown:
#Config(constants = BuildConfig.class, sdk =21, manifest="app/manifests/AndroidManifest.xml")
#RunWith(RobolectricTestRunner.class)
public class MultiFactorAPITest {
private MainActivity mainActivity;
#Mock
private MultiFactorAPI mockMultiFactorAPI;
#Captor
private ArgumentCaptor<Callback<List<ValidatePhoneUserResponse>>> callbackArgumentCaptor;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
ActivityController<MainActivity> controller = Robolectric.buildActivity(MainActivity.class);
mainActivity = controller.get();
// Then we need to swap the retrofit api impl. with a mock one
// We store our Retrofit api impl as a static singleton in class RestClient, hence:
RestClient.setApi(mockMultiFactorAPI);
controller.create();
}
The error is:
Annotation processors must be explicitly declared now. The following dependencies on the compile classpath are found to contain annotation processor. Please add them to the annotationProcessor configuration.
- auto-service-1.0-rc4.jar (com.google.auto.service:auto-service:1.0-rc4)
Alternatively, set android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true to continue with previous behavior. Note that this option is deprecated and will be removed in the future.
See https://developer.android.com/r/tools/annotation-processor-error-message.html for more details.
I've added these lines to gargle to:
dependencies {
implementation 'org.robolectric:robolectric:4.3'
implementation "org.mockito:mockito-core:1.10.19"
implementation 'org.hamcrest:hamcrest-library:1.1'
}
in gradle.Madule:
android{
testOptions {
unitTests {
includeAndroidResources = true
}
} }
in gradle.app:
dependencies{
classpath 'org.robolectric:robolectric-gradle-plugin:1.0.1'
}
in gradle.propertice:
android.enableUnitTestBinaryResources=true
android.enableAapt2=false
my problem solved by putting this code in my app.gradle :
dependencies{
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.okhttp3:mockwebserver:3.6.0'
}
and
1) find the location of of your .gradle folder, in Android Studio goto File->Settings and type "gradle" in the search box. You will be able to pick up the correct path there
2)Remove the .gradle directory (mine's location was C:\Users\UserName.gradle), and restart android studio. It will automatically create a new one.
from Android studio: build project error - Failed to complete Gradle execution

Where is the 'main' method of 'sourceSets' defined?

I'm going through some simple Gradle examples, and trying to get my head around the syntax. According to Gradle syntax, there must be a method called 'main' somewhere on 'sourceSets' (which is a SourceSetContainer) that takes a Closure. I figured that I would be able to find it by browsing around the Gradle javadocs, but I can't find it. Can someone point me to where 'main' is defined in this example?
apply plugin: 'java'
sourceSets {
main {
java {
srcDirs = ['src']
}
}
}
sourceSets is a container of named source sets. The java plugin adds a source set named main (and another named test) to that container. As such, there is no physical method or property called main. sourceSets.main { ... } could also be written as sourceSets.getByName("main") { ... }.

Is it possible to have 2 classes with the same name and in the same package?

I'm developing a grails app, and I need to modify a groovy class that is in a plugin, so I decided to override the class, so I have these method and class in my plugin:
def example = new a();
a.method();
class a {
void method() {
println "2";
}
}
all this was Inside the plugin, so I want to create another class in the same package in my project, to change the method, but how can I set my new class to run instead the plugin's? or is it impossible?
class a {
void method() {
println "4";
}
}
Yes, you just need to ensure that your class is on the classpath before the plugin's version.
Yes you can. It is called class shadowing. But I would advice against it most of the times. You only need to let the jvm load your class before the plugin class.

Is there any way to mock JNI methods in my android project to do Junit testing?

Hi I need to write Junit tests for an Android project but it has JNI methods as it uses webkit.Is there any way I can test those android methods(I dont want to test JNI methods).
Its like:
public void androidMethod(){
//some android code
nativeInit(); //how do I mock such methods?
//some code again
}
I have tried powermock,easymock,roboelectric but wasnt successful.Please help me.
I yesterday found I could solve this with Mockito (I didn't try powermock or easymock). Assuming your class is class C, my solution is:
C c=spy(new C);
doNothing().when(c).nativeInit();
c.androidMethod()
verify(c).nativeInit();
This does, of course, require that nativeInit is visible to the test.
Similar Problem
I had the same problem event though I was already using mockito in JUnit tests under src/test. Once I added tests under src/androidTest I started having issues, including this crash:
Mockito cannot mock/spy because :
- final class
And after making the class open, manually, I still got crashes in the JNI layer as it tried to load the *.so library (which wouldn't happen if mocks were working properly).
Working Solution
Instead, what I had to do was open the class for testing purposes using Kotlin's all-open plugin. The process is also explained well in this recent medium post but it boils down to the following four simple changes that are also modeled in one of the architecture components sample apps:
1. Make these additions to build.gradle:
buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-allopen:${versions.kotlin}"
}
}
apply plugin: "kotlin-allopen"
allOpen {
// marker for classes that we want to be able to extend in debug builds
annotation 'com.your.package.name.OpenClass'
}
2. Add the corresponding annotations in the debug flavor. For example: app/src/debug/java/com/your/package/name/OpenForTesting.kt
package com.your.package.name
#Target(AnnotationTarget.ANNOTATION_CLASS)
annotation class OpenClass
#OpenClass
#Target(AnnotationTarget.CLASS)
annotation class OpenForTesting
3. Add the corresponding annotation in the release flavor. For example: app/src/release/java/com/your/package/name/OpenForTesting.kt
package com.your.package.name
#Target(AnnotationTarget.CLASS)
annotation class OpenForTesting
4. Add the #OpenForTesting annotation to the class that needs to be mocked
package com.your.package.name
#OpenForTesting
class JniClassOfVictory {
...
external fun nativeInit()
...
companion object {
init {
System.loadLibrary("victoryeveryday")
}
}
}
The result is a flexible way to mark classes as open without actually making them open in release builds. Of course, this is because the #OpenForTesting annotation that we created in release is not marked with #OpenClass but the same annotation in debug is marked with #OpenClass. In build.gradle we designated that annotation as the signal to the kotlin-allopen plugin. So any class annotated with #OpenForTesting will be made open at compile-time but only on Debug builds.

Categories

Resources