I have model
#Data
#AllArgsConstructor
#NoArgsConstructor
public class ProductsRequest {
private String initiatorType;
private String categoryCode;
I have lombok config:
lombok.anyConstructor.suppressConstructorProperties = true
lombok.addGeneratedAnnotation = false
On android with API 27(Android 7 on real device) all work fine. On android 17(Android 4.2 on emulator) In this line I get error:
return restApiFactory.getProductService().getProducts(productsRequest);
error:
Caused by: java.lang.ClassNotFoundException: Didn't find class "java.beans.ConstructorProperties" on path: /data/app/my-1.apk
If I change
#AllArgsConstructor
#NoArgsConstructor
to standart constructors - all work fine
Because I never experienced such issue with ctor-s I encourage you to describe your problem in more detail. I assume the code you manually wrote somehow differs from the code lombok generated. Might be the visibility of methods or some special annotation added.
Using delombok feature (https://projectlombok.org/features/delombok) you will expand the annotations to real code. Than you can diff your manually written code and lombok generated code. So you can explore if #java.beans.ConstructorProperties added or not above the code lombok generated. (Delombok using Gradle)
Note: Actually you will have 3 ctor: #AllArgsConstructor, #NoArgsConstructor and #RequiredArgsConstructor is implicitly covered in #Data.
Based on your lombok.config file, ctor-s should not have an annotation. Could it be that some of your flavors are missing the lombok.config on class path?
Related
So I have an Android library project, SimpleWidget. I publish it to jcenter.
I can make a new project and add implementation 'my.project:simplewidget:1.2.3' and everything works as expected, I can use SimpleWidget instances and their public APIs.
Now I make another Android library project, ComplexWidget. ComplexWidget is a subclass of SimpleWidget. I add implementation 'my.project:simplewidget:1.2.3' to the build.gradle and everything resolves, and in fact I can even get away without lint yelling for something super basic like ComplexWidget complexWidget = new ComplexWidget().
However, the project will not compile. Any ComplexWidget method that has a return or parameter type of SimpleWidget (e.g., many of the inherited methods, or an interface that accepts SimpleWidget arguments, or a Factory that returns SimpleWidget instances) will not compile and Android Studio complains that "Cannot access my.project.SimpleWidget".
Not sure if I should even mention it for fear of muddying the waters, but if I command click SimpleWidget in, for example, public class ComplexWidget extends SimpleWidget, I get a warning at the top of the file that "Library source does not match the byetcode for the class SimpleWidget".
Any ideas?
TYIA
use api 'my.project:SimpleWidget:1.2.3' instead
I implemented Jacoco in my Android project using the following tutorial https://proandroiddev.com/unified-code-coverage-for-android-revisited-44789c9b722f to cater for test coverage in the kotlin classes.
For some unknown reason, it's not reporting coverage for static methods declared under the Companion block.
class Meh {
companion object {
fun test () {
// logic to test
}
}
However if I convert the class to an instance rather than a singleton that I am able to see the coverage completely fine.
Has anyone came across this problem ? and what did you do ?
following tutorial https://proandroiddev.com/unified-code-coverage-for-android-revisited-44789c9b722f
after cloning of example from the same tutorial in its state as of today (HEAD commit)
git clone https://github.com/rafaeltoledo/unified-code-coverage-android.git
cd unified-code-coverage-android
git checkout kotlin-coverage
addition of companion object into MainActivity
class MainActivity : AppCompatActivity() {
+ companion object {
+ fun executed() {
+ }
+
+ fun notExecuted() {
+ }
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
+ executed()
start of virtual device Pixel XL with API 28 and target Android 9.0 (Google APIs) in freshly downloaded Android Studio 3.2.1
and execution of
./gradlew jacocoTestReport
following report is produced in directory app/build/reports/jacoco/jacocoTestReport/html/ as expected
Given the amount of factors that influence result (such as versions of all involved components - Android SDK, Device, Kotlin compiler, Gradle, JaCoCo, etc, etc), attempts to guess what is different in your case are IMO counterproductive, and so that the best advice - is to perform very careful comparison of differences between your setup and above example.
Update
As was figured out during comparison by #HeWhoProtects , problem was in
exclusion of **/*$*
that refers to exclusion of class files from analysis. Single source file can compile into multiple class files, e.g. in case of nested classes in Java and exactly in case of companion in Kotlin and in both cases name of class and class file will contain $.
I found the the cause of the problem but not sure why it caused it yet, my excludes rules includes more rules than the one in the tutorial above, in different jacoco tutorial for ignoring autogenerated files, it was suggested to include '**/*$*' as rule, as soon as I removed it, it showed coverage for static methods in kotlin.
My understanding of Jacoco that these rules ignore files and will not show it in the report, and before I made the change, it was showing that this class is covered in the test coverage.... is it weird or am I missing a fundamental thing about how kotlin generates methods or how jacoco excludes rules work ?
Anyway I hope this helps..
The app defines constants in a Kotlin singleton object:
#file:JvmName("APIConstants")
package com.myapp.api
object APIConstants {
const val HTTP_RESPONSE_CODE_NOT_AUTHORIZED = 401
etc....
}
They are then used in another class:
import com.myapp.api.APIConstants.HTTP_RESPONSE_CODE_NOT_AUTHORIZED
etc ...
class API {
private fun returnBadResponse(response: Response<*>, callback: ApiAuthListener<*>) {
if (response.code() == HTTP_RESPONSE_CODE_NOT_AUTHORIZED) {
callback.onBadAuthToken()
} else {
callback.onFailure(response.message(), getServerError(response))
}
}
In this class Android Studio (3.0 beta) provided a hint to add the import for the constant, and it does not give any indication of a problem (no red underlines etc, and the constant reference in the method is shown in purple italic text indicating it has been resolved) but when I build the project I get this:
Error: Unresolved reference: HTTP_RESPONSE_CODE_NOT_AUTHORIZED
I've tried clearing the IDE cache and restarting it, and doing a clean build, which make no difference. I've tried removing the #JvmName annotation and even placing the const values in the root of the file with no containing object but neither allows a build.
Why is the class failing to reference the constant, especially when the IDE strongly suggests it can resolve it?
And the solution is.... to make very sure all Kotlin source files have a .kt file extension! In this case the APIConstants file was called "APIConstants" and not "APIConstants.kt" which appears to mean the IDE was able to resolve references based on the content of the file, but the build tools could not. Confusingly Android Studio showed a Kotlin K icon on the filename despite the lack of a .kt extension.
I would like to use the Scala (2.11) reflection package's runtime mirror in a Scala application compiled for android which is being build using Scala on android.
I was able to fiddle with ProGuard options in order to make it include the required Scala classes. However when I try to get a mirror instance:
universe.runtimeMirror(this.getClass.getClassLoader)
(Indeed it fails during the lazy computation of universe)
The application crashes in run time:
java.lang.NoClassDefFoundError: Failed resolution of: Ljava/rmi/Remote;
at scala.reflect.internal.Definitions$DefinitionsClass.RemoteInterfaceClass$lzycompute(Definitions.scala:370)
at scala.reflect.internal.Definitions$DefinitionsClass.RemoteInterfaceClass(D efinitions.scala:370)
at scala.reflect.runtime.JavaUniverseForce$class.force(JavaUniverseForce.scal a:255)
at scala.reflect.runtime.JavaUniverse.force(JavaUniverse.scala:16)
at scala.reflect.runtime.JavaUniverse.init(JavaUniverse.scala:147)
at scala.reflect.runtime.JavaUniverse.<init>(JavaUniverse.scala:78)
at scala.reflect.runtime.package$.universe$lzycompute(package.scala:17)
at scala.reflect.runtime.package$.universe(package.scala:17)
This crash is for me as expected as it isn't:
It is expected as java.rmi is not part of the Android API and I should expect any code trying to load its classes to crash.
It is unexpected as I didn't know that Scala's reflect package used java.rmi
I have traced the code to were rmi is required, that is to JavaUniverse (a trait mixed in JavaUniverse class) force method:
...
definitions.RemoteInterfaceClass
...
Which leads to DefinitionsClass:
lazy val RemoteInterfaceClass = requiredClass[java.rmi.Remote]
Am I wrong to think that this is a no-go for Scala reflection in Android?
If I am, what could be a workaround to this problem?
To summarize your solution and a related solution, it is sufficient to add two files, and modify build.sbt to include:
dexAdditionalParams in Android += "--core-library"
Add java/rmi/Remote.java to your project with the content:
package java.rmi;
public interface Remote {}
Add java/rmi/RemoteException.java to your project with the content:
package java.rmi;
public interface RemoteException {}
Like many others I was excited to hear that Mockito now works with Android and followed this tutorial to see it with my own eyes. Everything seemed fan-flapping-tastic and I got underway incorporating the mocking solution into my Android Test Project...
The error
However, on setting up my application's test project to leverage the mockito-all-1.9.5, dexmaker-1.0 and dexmaker-mockito-1.0 jars I encountered a problem with my very first test case. Precisely this problem in fact. The part that I would like assistance on is;
Caused by: java.lang.VerifyError: org/mockito/cglib/core/ReflectUtils
at org.mockito.cglib.core.KeyFactory$Generator.generateClass(KeyFactory.java:167)
at org.mockito.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:217)
at org.mockito.cglib.core.KeyFactory$Generator.create(KeyFactory.java:145)
at org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:117)
at org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:109)
at org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:105)
at org.mockito.cglib.proxy.Enhancer.<clinit>(Enhancer.java:70)
I have been informed that this "simply doesn't quite work yet" since the stack trace implies that the DexMaker jar is not being used - reference this response. However, I am suspicious that I am doing something wrong with respect to my project set-up so I'm looking to draw from the collective knowledge base here to see if indeed this is user error or a beta-bug.
My Android Test Project set-up
Please find below a screenshot of my test project's configuration. The project was created via the Android Wizard and shares no special features other than the inclusion of the Mockito and DexMaker jars (mentioned above) under the libs directory.
The Test
Never mind the content of the test (the test fails before the unit test is executed) the set-up is as described below;
public class TestSpotRatingCalculator extends InstrumentationTestCase {
#Mock
private AService aService; // Changed the service names being used here - not important.
#Mock
private BService bService;
#Mock
private CService cService;
#Mock
private DService dService;
/**
* #see android.test.AndroidTestCase#setUp()
*/
#Override
protected void setUp() throws Exception {
super.setUp();
MockitoAnnotations.initMocks(this); // Failure here with aforementioned stacktrace...
}
If anyone out there has an idea what is wrong then please sound-off here.
Hi I had the same problem and I found this article really usefull!
http://corner.squareup.com/2012/10/mockito-android.html
The key piece of information is:
To use Mockito on a device or emulator, you’ll need to add three .jar
files to your test project’s libs directory: mockito-all-1.9.5.jar,
dexmaker-1.0.jar, and dexmaker-mockito-1.0.jar.
Just add this in your gradle:
androidTestCompile 'org.mockito:mockito-core:1.10.8'
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.1'
We just had the same problem in a project, but our tests also failed on a real device.
The cause was tracked to how Mockito uses the class loader, and resulted in the following error in LogCat:
W/ActivityThread(5777): ClassLoader.getResources: The class loader returned by Thread.getContextClassLoader() may fail for processes that host multiple applications. You should explicitly specify a context class loader. For example: Thread.setContextClassLoader(getClass().getClassLoader());
The fix was to explicitly set the class loader before calling mock() a test, eg.
#Override
protected void setUp() throws Exception {
super.setUp();
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
fooImpl = mock(Foo.class)
}
The problematic file in Mockito is this one: org.mockito.internal.configuration.ClassPathLoader (line 121 in 1.9.5)
As hinted at here the dexmaker-android combo only works 100% when the instrumented tests are run against a real device.
Running the tests against a real device do not exhibit this failure.
For everybody who still have this error, check if you didn't exclude a class in the dependecies. We exluded by accident the MockMaker.class so this was then the cause for the exception.