Objectbox-java: Cannot convert List<> of custom class to String in Objectbox

Created on 21 Jun 2018  路  5Comments  路  Source: objectbox/objectbox-java

Hey guys, I love your project! I'm having trouble getting this to work though. I can't seem to figure out what I'm doing wrong, which is making me wonder if it's a bug.

Issue Basics

  • Using the latest version 1.5.0
  • This occurs every time I attempt to build my project

Reproducing the bug

I have a custom entity class that has two lists of another custom class. I defined a converter for each of those lists to convert the list into a JSON string using Gson. When I attempt to build the project, I'm given the error message Cause: cannot find constructor io.objectbox.relation.ToMany(com.stoicapps.roll4initiative.models.Encounter,io.objectbox.Property).

Code

So the class with the lists is the Encounter class:

@Entity
public class Encounter {

    @Id
    private long id;

    private String name;

    private int currentRound;

    @Convert(converter =  EncounterParticipantConverter.class, dbType = String.class)
    private List<Creature> livingParticipants;

    @Convert(converter =  EncounterParticipantConverter.class, dbType = String.class)
    private List<Creature> deadParticipants;

    private int currentTurnIndex;
    private long uniqueIdentifier;

    ...

Here's the Creature class:

@Entity
public class Creature {

    @Id
    private long id;

    @Convert(converter =  CreatureTypeConverter.class, dbType = Integer.class)
    private CreatureType type;

    @Index
    private String name;

    @Convert(converter = DiceRollConverter.class, dbType = String.class)
    private DiceRoll initiativeDiceRoll;
    private int initiativeValue;

    @Convert(converter = DiceRollConverter.class, dbType = String.class)
    private DiceRoll hitPointsDiceRoll;
    private int hitPointsValue;

Here's the converter for the lists in the Encounter class:

public static class EncounterParticipantConverter implements PropertyConverter<List<Creature>, String> {

        @Override
        public List<Creature> convertToEntityProperty(String jsonString) {
            if (jsonString == null) {
                return null;
            }

            return new Gson().fromJson(jsonString, new TypeToken<List<Creature>>(){}.getType());
        }

        @Override
        public String convertToDatabaseValue(List<Creature> creatureList) {
            if (creatureList == null) {
                return null;
            }

            return new Gson().toJson(creatureList);
        }
    }

Let me know if you need to see anything else.

Logs & stackstraces

Here's the full stack trace:

org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:objectboxTransformDebugUnitTest'.
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:100)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:70)
    at org.gradle.api.internal.tasks.execution.OutputDirectoryCreatingTaskExecuter.execute(OutputDirectoryCreatingTaskExecuter.java:51)
    at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:62)
    at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:54)
    at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:60)
    at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:97)
    at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:87)
    at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:52)
    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:626)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.executeWithTask(DefaultTaskExecutionPlan.java:581)
    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 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
    at java.lang.Thread.run(Thread.java:745)
Caused by: io.objectbox.gradle.transform.TransformException: Could not transform class "com.stoicapps.roll4initiative.models.Encounter" (Could not insert init code for field livingParticipants in constructor)
    at io.objectbox.gradle.transform.ClassTransformer.transformEntityAndBases(ClassTransformer.kt:146)
    at io.objectbox.gradle.transform.ClassTransformer.transformEntities(ClassTransformer.kt:117)
    at io.objectbox.gradle.transform.ClassTransformer.transformOrCopyClasses(ClassTransformer.kt:95)
    at io.objectbox.gradle.transform.ObjectBoxJavaTransform.transform(ObjectBoxJavaTransform.kt:47)
    at io.objectbox.gradle.transform.ObjectBoxAndroidTransform$Registration$injectTransformTask$1.execute(ObjectBoxAndroidTransform.kt:131)
    at io.objectbox.gradle.transform.ObjectBoxAndroidTransform$Registration$injectTransformTask$1.execute(ObjectBoxAndroidTransform.kt:52)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:780)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:747)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$1.run(ExecuteActionsTaskExecuter.java:121)
    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.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:110)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:92)
    ... 32 more
Caused by: io.objectbox.gradle.transform.TransformException: Could not insert init code for field livingParticipants in constructor
    at io.objectbox.gradle.transform.ClassTransformer.transformConstructors(ClassTransformer.kt:281)
    at io.objectbox.gradle.transform.ClassTransformer.transformEntity(ClassTransformer.kt:186)
    at io.objectbox.gradle.transform.ClassTransformer.transformEntityAndBases(ClassTransformer.kt:142)
    ... 46 more
Caused by: javassist.CannotCompileException: [source error] cannot find constructor io.objectbox.relation.ToMany(com.stoicapps.roll4initiative.models.Encounter,io.objectbox.Property)
    at javassist.CtConstructor.insertBeforeBody(CtConstructor.java:273)
    at io.objectbox.gradle.transform.ClassTransformer.transformConstructors(ClassTransformer.kt:279)
    ... 48 more
Caused by: compile error: cannot find constructor io.objectbox.relation.ToMany(com.stoicapps.roll4initiative.models.Encounter,io.objectbox.Property)
    at javassist.compiler.TypeChecker.atMethodCallCore(TypeChecker.java:749)
    at javassist.compiler.TypeChecker.atNewExpr(TypeChecker.java:149)
    at javassist.compiler.ast.NewExpr.accept(NewExpr.java:73)
    at javassist.compiler.TypeChecker.atFieldAssign(TypeChecker.java:276)
    at javassist.compiler.JvstTypeChecker.atFieldAssign(JvstTypeChecker.java:84)
    at javassist.compiler.TypeChecker.atAssignExpr(TypeChecker.java:230)
    at javassist.compiler.ast.AssignExpr.accept(AssignExpr.java:39)
    at javassist.compiler.CodeGen.doTypeCheck(CodeGen.java:242)
    at javassist.compiler.CodeGen.atStmnt(CodeGen.java:330)
    at javassist.compiler.ast.Stmnt.accept(Stmnt.java:50)
    at javassist.compiler.Javac.compileStmnt(Javac.java:567)
    at javassist.CtConstructor.insertBeforeBody(CtConstructor.java:261)
    ... 49 more

Misc

There isn't anything special about my app, especially with what I'm trying to do here.

bug

Most helpful comment

Alright, added tests and built fix. This should be released with the next preview (or final) release of 2.0.0.

Please re-open if the next release does not fix this issue.
-ut

All 5 comments

It looks like a good workaround for this issue is to specify a type of List--I changed those fields from List to ArrayList and everything works fine. Regardless, I think overriding the List relation type should work fine, but that of course is up to you guys.

Maybe we can detect the @Convert and skip it for relation detection, @greenrobot-team ?

The processor correctly ignores @Convert fields of type List. But the bytecode transformer does not. Guess that bug slipped by, because we have no tests where @Convert is of type List. 馃槺

Will add those now and work on fix.
-ut

Alright, added tests and built fix. This should be released with the next preview (or final) release of 2.0.0.

Please re-open if the next release does not fix this issue.
-ut

Try with 2.0.0-beta2

Was this page helpful?
0 / 5 - 0 ratings