6

I've tried to migrate a google cloud project using JDO from endpoints v1 to v2. I've followed the migration guide and some solutions here to try to make the datanucleous plugin enhance my classes, and upload them to the google cloud, but there is no luck.

I'm gonna post the build.gradle followed by the server error returned when a client tries to connect to an endpoint, which is a NoClassFound error.

build.gradle:

buildscript {
    repositories {
        mavenCentral()
        mavenLocal()
    }
    dependencies {
        // App Engine Gradle plugin
        classpath 'com.google.cloud.tools:appengine-gradle-plugin:1.3.3'

        // Endpoints Frameworks Gradle plugin
        classpath 'com.google.cloud.tools:endpoints-framework-gradle-plugin:1.0.2'

    }
}

repositories {
    mavenCentral();
    jcenter()
}

apply plugin: 'java'
apply plugin: 'war'

// [START apply_plugins]
apply plugin: 'com.google.cloud.tools.appengine'
apply plugin: 'com.google.cloud.tools.endpoints-framework-server'
// [END apply_plugins]

dependencies {
    compile ('com.google.endpoints:endpoints-framework:2.0.8') {
        exclude group: 'com.google.guava', module: 'guava-jdk5'
    }

    compile 'javax.servlet:servlet-api:2.5'
    compile 'com.ganyo:gcm-server:1.0.2'
    compile 'javax.jdo:jdo-api:3.0.1'
    compile 'org.datanucleus:datanucleus-core:3.1.3'
    compile 'org.datanucleus:datanucleus-api-jdo:3.1.3'
    compile 'org.datanucleus:datanucleus-accessplatform-jdo-rdbms:4.1.1'
    compile 'com.google.appengine.orm:datanucleus-appengine:2.1.2'
    compile 'com.google.code.gson:gson:2.2.4'
    compile 'org.apache.commons:commons-lang3:3.5'
}

sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7

appengine {  // App Engine tasks configuration
    deploy {   // deploy configuration
        version = findProperty("appengine.deploy.version")

        def promoteProp = findProperty("appengine.deploy.promote")
        if (promoteProp != null) {
            promote = new Boolean(promoteProp)
        }

    }
}

endpointsServer {
    // Endpoints Framework Plugin server-side configuration
    hostname = "komilibro.appspot.com"
}

task datanucleusEnhance {
    description "Enhance JDO model classes using DataNucleus Enhancer"
    dependsOn processResources

    doLast {
        // define the entity classes
        def entityFiles = fileTree(sourceSets.main.output.classesDir).matching {
            include 'com/meanwhile/komi/head/**/*.class'
        }

        println "Enhancing with DataNucleus the following files"
        entityFiles.getFiles().each {
            println it
        }

        // define Ant task for DataNucleus Enhancer
        ant.taskdef(
                name : 'datanucleusenhancer',
                classpath : sourceSets.main.runtimeClasspath.asPath,
                classname : 'org.datanucleus.enhancer.EnhancerTask'
                // the below is for DataNucleus Enhancer 3.1.1
                //classname : 'org.datanucleus.enhancer.tools.EnhancerTask'
        )

        // run the DataNucleus Enhancer as an Ant task
        ant.datanucleusenhancer(
                classpath: sourceSets.main.runtimeClasspath.asPath,
                verbose: true,
                api: "JDO") {
            entityFiles.addToAntBuilder(ant, 'fileset', FileCollection.AntType.FileSet)
        }
    }
}

classes.dependsOn(datanucleusEnhance)

Taking a look to the server logs after a user request, I can see two errors: first:

    org.datanucleus.store.types.TypeManagerImpl loadJavaTypes: User-defined type
 mapping class "org.datanucleus.store.types.sco.simple.Collection" was not found.
 Please check the mapping file class specifications and your CLASSPATH. The class
 must be in the CLASSPATH. 

And this is the second. PMF is just a class used to load and instance of the PersistenceManager.

com.google.api.server.spi.SystemService invokeServiceMethod: exception occurred while calling backend method (SystemService.java:375)
java.lang.NoClassDefFoundError: Could not initialize class com.meanwhile.komi.head.PMF

So, seems like the classes needed are not in place, but also the TypeManagerImpl does not find the Collection class (default java Collection is used in the endpoints). I'm a little lost here, so help is really welcome.

Thanks!

Ying Li
  • 2,500
  • 2
  • 13
  • 37
juanmeanwhile
  • 2,594
  • 2
  • 24
  • 26
  • Why would you put datanucleus-accessplatform-jdo-rdbms v4.x in the CLASSPATH when this Google appengine stuff won't work with versions like that? What do Google's docs tell you to do? This datanucleus-accessplatform-jdo-rdbms is not even mentioned (and you aren't using RDBMS so why would you even consider it?) –  Aug 12 '18 at 14:30
  • Well, the reason is as simply as that it is an old project which I don’t have much knowledge about. Google docs doesn’t support jdo anymore, so no much info there. Thanks for the hint, I’ll give that a try – juanmeanwhile Aug 13 '18 at 22:30
  • Did you follow [this](https://cloud.google.com/endpoints/docs/frameworks/java/migrating) steps to perform the migration? If not, please do so. – komarkovich Aug 15 '18 at 10:21
  • Thanks @komarkovich, I did follow that and my endpoints are deployed successfully. The problem is that the migration guide does not provide support for jdo so I'm not sure if the classes are being enhanced and uploaded properly – juanmeanwhile Aug 30 '18 at 13:15

2 Answers2

1

At the very end of this migration page, there is a section labeled "Issues with JPA/JDO Datanucleus enhancement," which links to a StackOverflow example with a working gradle configuration for Datanucleus. I would look very closely for any differences between this canonical example and your own gradle build file.

1

Add this in your gradle build file:

task datanucleusEnhance {
  description "Enhance JDO model classes using DataNucleus Enhancer"
  dependsOn compileJava

  doLast {    
      // define the entity classes
      def entityFiles = fileTree(sourceSets.main.output.classesDir).matching {
          include 'com/mycom/*.class', 'org/myorg/*.class'
      }

      println "Enhancing with DataNucleus the following files"
      entityFiles.getFiles().each {
          println it
      }

      // define Ant task for DataNucleus Enhancer
      ant.taskdef(
          name : 'datanucleusenhancer',
          classpath : sourceSets.main.runtimeClasspath.asPath,
          classname : 'org.datanucleus.enhancer.EnhancerTask'
          // the below is for DataNucleus Enhancer 3.1.1
          //classname : 'org.datanucleus.enhancer.tools.EnhancerTask'
      )

      // run the DataNucleus Enhancer as an Ant task
      ant.datanucleusenhancer(
          classpath: sourceSets.main.runtimeClasspath.asPath,
          verbose: true,
          api: "JDO") {
          entityFiles.addToAntBuilder(ant, 'fileset', FileCollection.AntType.FileSet)
      }
  }
}

classes.dependsOn(datanucleusEnhance)

The entityFiles is where you configure your JPA entity annotated classes.

juanmeanwhile
  • 2,594
  • 2
  • 24
  • 26
Ying Li
  • 2,500
  • 2
  • 13
  • 37
  • Also, it was important to me that with Java 7 you should be using Enhancer 3.1.1 and compile 'org.datanucleus:datanucleus-core:3.1.3' compile 'org.datanucleus:datanucleus-api-jdo:3.1.3' – juanmeanwhile Sep 11 '18 at 13:44