Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ncLineCount column gives error #135

Closed
freshcodemonger opened this issue Apr 5, 2019 · 17 comments
Closed

ncLineCount column gives error #135

freshcodemonger opened this issue Apr 5, 2019 · 17 comments
Assignees
Labels

Comments

@freshcodemonger
Copy link

freshcodemonger commented Apr 5, 2019

report {
//...
columns {
//..
ncLineCount format: 'raw'
//...

https://confluence.atlassian.com/clover/clover-report-71600095.html#clover-report-Columns

* What went wrong:
Unable to store input properties for task ':cloverReport'. Property 'additionalColumns' with value
 '[com.bmuschko.gradle.clover.CloverReportColumn@1ccec4a6, 
com.bmuschko.gradle.clover.CloverReportColumn@4f828e6c, 
com.bmuschko.gradle.clover.CloverReportColumn@465ea763, 
com.bmuschko.gradle.clover.CloverReportColumn@716b1c17, 
com.bmuschko.gradle.clover.CloverReportColumn@135e0330]' cannot be serialized.
> java.lang.ClassNotFoundException: com.bmuschko.gradle.clover.CloverReportColumn

@Alex-Vol-SV
Copy link
Collaborator

I have not seen this one before. It will take some time to investigate.

@freshcodemonger
Copy link
Author

Here is the stack if that helps

* Exception is:
org.gradle.api.UncheckedIOException: Unable to store input properties for task ':cloverReport'. Property 'additionalColumns' with value '[com.bmuschko.gradle.clover.CloverReportColumn@1d83a008, com.bmuschko.gradle.clover.CloverReportColumn@62d47126, com.bmuschko.gradle.clover.CloverReportColumn@2d13d16d, com.bmuschko.gradle.clover.CloverReportColumn@745fe8a1, com.bmuschko.gradle.clover.CloverReportColumn@450f255f]' cannot be serialized.
        at org.gradle.api.internal.changedetection.state.CacheBackedTaskHistoryRepository.snapshotTaskInputProperties(CacheBackedTaskHistoryRepository.java:312)
        at org.gradle.api.internal.changedetection.state.CacheBackedTaskHistoryRepository.createExecution(CacheBackedTaskHistoryRepository.java:146)
        at org.gradle.api.internal.changedetection.state.CacheBackedTaskHistoryRepository.access$100(CacheBackedTaskHistoryRepository.java:61)
        at org.gradle.api.internal.changedetection.state.CacheBackedTaskHistoryRepository$1.getCurrentExecution(CacheBackedTaskHistoryRepository.java:111)
        at org.gradle.api.internal.changedetection.changes.DefaultTaskArtifactStateRepository$TaskArtifactStateImpl.getStates(DefaultTaskArtifactStateRepository.java:203)
        at org.gradle.api.internal.changedetection.changes.DefaultTaskArtifactStateRepository$TaskArtifactStateImpl.isUpToDate(DefaultTaskArtifactStateRepository.java:89)
        at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:50)
        at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:54)
        at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:59)
        at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:101)
        at org.gradle.api.internal.tasks.execution.FinalizeInputFilePropertiesTaskExecuter.execute(FinalizeInputFilePropertiesTaskExecuter.java:44)
        at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:88)
        at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:62)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
        at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
        at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.run(DefaultTaskGraphExecuter.java:248)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:241)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:230)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.processTask(DefaultTaskPlanExecutor.java:123)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.access$200(DefaultTaskPlanExecutor.java:79)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:104)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:98)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.execute(DefaultTaskExecutionPlan.java:623)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.executeWithTask(DefaultTaskExecutionPlan.java:578)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.run(DefaultTaskPlanExecutor.java:98)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
        at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
Caused by: org.gradle.api.UncheckedIOException: java.lang.ClassNotFoundException: com.bmuschko.gradle.clover.CloverReportColumn
        at org.gradle.api.internal.changedetection.state.SerializedValueSnapshot.populateClass(SerializedValueSnapshot.java:106)
        at org.gradle.api.internal.changedetection.state.SerializedValueSnapshot.hasSameSerializedValue(SerializedValueSnapshot.java:70)
        at org.gradle.api.internal.changedetection.state.SerializedValueSnapshot.snapshot(SerializedValueSnapshot.java:51)
        at org.gradle.api.internal.changedetection.state.ValueSnapshotter.snapshot(ValueSnapshotter.java:209)
        at org.gradle.api.internal.changedetection.state.CacheBackedTaskHistoryRepository.snapshotTaskInputProperties(CacheBackedTaskHistoryRepository.java:309)
        ... 33 more
Caused by: java.lang.ClassNotFoundException: com.bmuschko.gradle.clover.CloverReportColumn
        at org.gradle.internal.io.ClassLoaderObjectInputStream.resolveClass(ClassLoaderObjectInputStream.java:40)
        at org.gradle.api.internal.changedetection.state.SerializedValueSnapshot.populateClass(SerializedValueSnapshot.java:104)
        ... 37 more


* Get more help at https://help.gradle.org

Deprecated Gradle features were used in this build, making it incompatible with Gradle 5.0.
See https://docs.gradle.org/4.5.1/userguide/command_line_interface.html#sec:command_line_warnings

@Alex-Vol-SV
Copy link
Collaborator

This stacktrace helps pinpoint the particular details I need to fix it.
I think the newer versions of Gradle try to snapshot the state of input properties deeper than before and cause this issue.

@Alex-Vol-SV
Copy link
Collaborator

How do you add the Clover plugin in your projects? This seems to be a classpath issue more than a class serialization issue. The classes are properly serializable for the particular ones involved here.

@freshcodemonger
Copy link
Author

I have them extracted to their own gradle include files but that requires calling out the full package names.

import com.bmuschko.gradle.clover.CloverPlugin
import com.bmuschko.gradle.clover.GenerateCoverageReportTask

...
dependencies {
classpath 'com.bmuschko:gradle-clover-plugin:2.2.2'
}
...

apply plugin: com.bmuschko.gradle.clover.CloverPlugin

dependencies {
    clover 'org.openclover:clover:4.3.1'
}

@Alex-Vol-SV
Copy link
Collaborator

That is probably why it fails. Are you adding the clover plugin in the top level build.gradle classpath or are you adding it in a separate included apply from: 'clover.gradle'?

I know that classpath additions in included gradle scripts are cause for classpath issues of this kind.

@Alex-Vol-SV
Copy link
Collaborator

Alex-Vol-SV commented Apr 8, 2019

I always make my classpath declarations only in the top build.gradle. I add configuration blocks in separate gradle scripts.

FYI, using buildscript classpath dependencies in included gradle modules will be deprecated and removed in a future version of Gradle as far as I know. It is known to be a common cause for classpath issues like the one you are describing here.

@freshcodemonger
Copy link
Author

I didn't know that. I just hacked the gradle stuff together so open for improvements. I'll try to move the classpath dependency to build.gradle and see if that helps. Thank you !

@freshcodemonger
Copy link
Author

I worked out the problem. Moving the classpath dependencies wasn't the solution.

Gradle creates a cache directory in your project called .gradle, gradle clean does not clean this.

If you change the columns in the report after running once and rebuild without removing the .gradle directory it will fail. I don't know exactly what output gradle has cached that causes this problem. If you generate a clover report and then change the columns do you not see the same problem? I don't think I have anything other than default gradle caching enabled.

@Alex-Vol-SV
Copy link
Collaborator

That is how Gradle works. The task inputs for the previous successfully executed tasks are cached in the .gradle directory in the root of your project. When Gradle needs to check your task for up to date conditions it will attempt to deserialize the cached inputs. At that point the classpath is important and will need to have the plugin classes to allow the deserialization to succeed. You should not need to remove this directory except when plugins change in incompatible ways. This particular class in the plugin has not changed since many iterations ago. So, I doubt what you are having issues with it any of my problem. All I can see from the stacktrace is that the class was not found which signals me to suspect your nested script classpath configuration.

@freshcodemonger
Copy link
Author

I agree with you about how gradle works but independent of if you have the classpath dependencies in the main gradle file - as I tried this - re-running after changing a column will not work unless you wipe that .gradle directory. I can't speak to if this is a bug but it seems odd that I'd have to delete the .gradle directory after changing the column configuration in order for the report to work again. Did you give that a try on your end and see if you can run, change the columns, and re-run a build successfully?

@Alex-Vol-SV
Copy link
Collaborator

I have to try this myself and find out why it fails. The classnotfound error is a classpath error and there is not much I can do about that. I do not control the classpath Gradle uses for finding the plugin classes. As you see from the stacktrace you provided there is no code stack trace from this plugin in the entire stack so even if I wanted to try I would not have any way to change it.

So, I cannot promise you that I will be able to figure this out easily. It is not within this plugin execution path.

@Alex-Vol-SV
Copy link
Collaborator

I can certainly reproduce this easily with a simple project. I suspect this never worked well and had such an issue since I added the feature but as it is an obscure kind of feature not many people use it. If I am correct the problem might be that Gradle cannot handle task inputs with custom task types, it prefers simple primitive types and collections of the same or any Gradle provided types. This might mean that I would have to come up with a metadata representation of the columns when I attach them as task inputs and convert them in the task instead. The behavior implemented right now takes the DSL implementation classes which are correctly serializable and uses them as task inputs in a collection.

@Alex-Vol-SV Alex-Vol-SV reopened this Apr 9, 2019
@Alex-Vol-SV Alex-Vol-SV added Bug and removed Not a bug labels Apr 9, 2019
@freshcodemonger
Copy link
Author

Ok thanks for looking at it and all the work on the plugin! I can work around the issue by just deleting the .gradle directory if I change the column format. It just took a lot of testing to figure out that was the issue. Probably just add some documentation for now and put it at the back of the pile - at least there is a work around.

@Alex-Vol-SV
Copy link
Collaborator

You will probably find that this fails if the code is changed and you rebuild the project incrementally. Any time the task cloverGenerateReport or cloverAggregateReports needs to execute the same kind of failure will happen if the task has executed successfully once before. It is standard incremental build issue with Gradle.

I think the solution is actually not hard to implement now that you brought this to my attention. Understanding why this was broken in the first place was the hard part. Now that I can make it happen easily it will not be long before it can be fixed the right way.

@freshcodemonger
Copy link
Author

Sounds great ! Thank you !

Alex-Vol-SV added a commit that referenced this issue Apr 22, 2019
This issue was caused by the fact that Gradle task properties must not
use classes other than Gradle classes or Java classes. Using plugin
implementation classes as task inputs results in ClassNotFound errors
when incremental compilation attempts to deserialize the cached task
inputs. The fix was accomplished by using JSON strings to represent
the more complex data structures used for the custom Clover report
columns feature. This ensures the task inputs can be deserialized
and works incrementally.
@Alex-Vol-SV
Copy link
Collaborator

Fixed in release 2.2.3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants