Bug 426 : ebean-maven-enhancer throws ClassNotFoundException when entity class refers to external definitions
Priority 
High
Reported Version 
 
Logged By 
sr
Status 
Fixed
Fixed Version 
github
Assigned To 
 
Product 
Ebean - core
Duplicate Of 
 
Created 
19/09/2012
Updated 
19/09/2012
Type 
Bug
 
Attachments 
No attachments

The plugin throws ClassNotFound exception whenever a (model) class under consideration implements an interface whose definition resides inside an artifact. For example, one of my model classes implements ApplicationContextAware interface from the spring framework. The interface definition is inside a jar that is not part of class sources (specified via ${classSource}).

Although, the plugin does allow for user-specified classpath via ${classpath}, I couldn't find a portable way to pass it; e.g., ${maven.compile.classpath} resolves to null.
Instead I've patched the plugin to default to the project's (compile time) classpath by reconstructing it from the injected MavenProject instance. The patch fixes my problem, and I also believe it should address the problem mentioned here:

https://groups.google.com/forum/?fromgroups=#!searchin/ebean/ClassNotFoundException/ebean/AkFIZW_
g3M/7xAkeYy_Tz0J


I don't see an attachment option, so here is the patch inlined:
==========================================


Index: src/main/java/com/avaje/ebean/enhance/maven/MavenEnhanceTask.java
===================================================================
--- src/main/java/com/avaje/ebean/enhance/maven/MavenEnhanceTask.java (revision 1517)
+++ src/main/java/com/avaje/ebean/enhance/maven/MavenEnhanceTask.java (working copy)
@@ -1,10 +1,15 @@
package com.avaje.ebean.enhance.maven;

import java.io.File;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;

+import org.apache.commons.lang.StringUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;

import com.avaje.ebean.enhance.agent.Transformer;
import com.avaje.ebean.enhance.ant.OfflineFileTransform;
@@ -20,7 +25,8 @@
* The parameters are:
*


    *
  • classSource This is the root directory where the .class files are
    - * found. If this is left out then this defaults to ${project.build.outputDirectory}.

  • + * found. If this is left out then this defaults to
    + * ${project.build.outputDirectory}.
    *
  • classDestination This is the root directory where the .class files
    * are written to. If this is left out then this defaults to the
    * classSource.

  • @@ -68,89 +74,115 @@
    * @see com.avaje.ebean.enhance.ant.AntEnhanceTask
    * @goal enhance
    * @phase process-classes
    + *
    + * @requiresDependencyResolution compile
    + *
    */
    public class MavenEnhanceTask extends AbstractMojo {
    - /**
    - * the classpath used to search for e.g. inherited classes
    - *
    - * @parameter
    - */
    - private String classpath;
    + /**
    + * The maven project.
    + *
    + * @parameter expression="${project}"
    + * @required
    + * @readonly
    + */
    + protected MavenProject project;

    - /**
    - * Set the directory holding the class files we want to transform.
    - *
    - * @parameter default-value="${project.build.outputDirectory}"
    - */
    - private String classSource;
    + /**
    + * the classpath used to search for e.g. inherited classes
    + *
    + * @parameter
    + */
    + private String classpath;

    - /**
    - * Set the destination directory where we will put the transformed classes.
    - *


    - * This is commonly the same as the classSource directory.
    - *


    - *
    - * @parameter
    - */
    - String classDestination;
    + /**
    + * Set the directory holding the class files we want to transform.
    + *
    + * @parameter default-value="${project.build.outputDirectory}"
    + */
    + private String classSource;

    - /**
    - * Set the arguments passed to the transformer.
    - *
    - * @parameter
    - */
    - String transformArgs;
    + /**
    + * Set the destination directory where we will put the transformed classes.
    + *


    + * This is commonly the same as the classSource directory.
    + *


    + *
    + * @parameter
    + */
    + private String classDestination;

    - /**
    - * Set the package name to search for classes to transform.
    - *


    - * If the package name ends in "/**" then this recursively transforms all sub
    - * packages as well.
    - *


    - *
    - * @parameter
    - */
    - String packages;
    + /**
    + * Set the arguments passed to the transformer.
    + *
    + * @parameter
    + */
    + private String transformArgs;

    - public void execute() throws MojoExecutionException {
    + /**
    + * Set the package name to search for classes to transform.
    + *


    + * If the package name ends in "/**" then this recursively transforms all
    + * sub packages as well.
    + *


    + *
    + * @parameter
    + */
    + private String packages;

    - final Log log = getLog();
    - if (classSource == null) {
    - classSource = "target/classes";
    - }
    + public void execute() throws MojoExecutionException {
    + final Log log = getLog();

    - if (classDestination == null) {
    - classDestination = classSource;
    - }
    + if (classSource == null) {
    + classSource = "target" + System.getProperty("file.separator") + "classes";
    + }

    - File f = new File("");
    - log.info("Current Directory: " + f.getAbsolutePath());
    + if (classDestination == null) {
    + classDestination = classSource;
    + }
    + File f = new File("");
    + log.info("Current Directory: " + f.getAbsolutePath());

    - StringBuilder extraClassPath = new StringBuilder();
    - extraClassPath.append(classSource);
    - if (classpath != null) {
    - if (!extraClassPath.toString().endsWith(";")) {
    - extraClassPath.append(";");
    - }
    - extraClassPath.append(classpath);
    - }
    - Transformer t = new Transformer(extraClassPath.toString(), transformArgs);
    - ClassLoader cl = MavenEnhanceTask.class.getClassLoader();
    + String pathSeparator = System.getProperty("path.separator");
    + Set allClassPathElements = new HashSet();
    + allClassPathElements.addAll(Arrays.asList(StringUtils.split(classSource, pathSeparator)));

    - log.info("classSource=" + classSource + " transformArgs=" + transformArgs
    - + " classDestination=" + classDestination + " packages="+ packages);
    + if (classpath == null) {
    + log.info("'classpath' is null; will use project's classpath");
    + Set compileClassPathElements;

    - OfflineFileTransform ft = new OfflineFileTransform(t, cl, classSource, classDestination);
    - ft.setListener(new TransformationListener() {
    + try {
    + compileClassPathElements = new HashSet(project.getCompileClasspathElements());
    + } catch (Exception e) {
    + throw new MojoExecutionException(
    + "Unable to retrieve classpath elements", e);
    + }
    + allClassPathElements.addAll(compileClassPathElements);
    + }
    + // TODO: ebean internals are expecting ";" in place of
    + // ${path.separator}; e.g., see Transformer.parseClassPaths
    + String derivedClassPath = StringUtils.join(allClassPathElements, ";");
    + log.debug("Using classpath: " + derivedClassPath);

    - public void logEvent(String msg) {
    - log.info(msg);
    - }
    + Transformer t = new Transformer(derivedClassPath, transformArgs);
    + ClassLoader cl = MavenEnhanceTask.class.getClassLoader();

    - public void logError(String msg) {
    - log.error(msg);
    - }
    - });
    - ft.process(packages);
    - }
    -}
    \ No newline at end of file
    + log.info("classSource=" + classSource + " transformArgs="
    + + transformArgs + " classDestination=" + classDestination
    + + " packages=" + packages);
    +
    + OfflineFileTransform ft = new OfflineFileTransform(t, cl, classSource,
    + classDestination);
    + ft.setListener(new TransformationListener() {
    +
    + public void logEvent(String msg) {
    + log.info(msg);
    + }
    +
    + public void logError(String msg) {
    + log.error(msg);
    + }
    + });
    + ft.process(packages);
    + }
    +}
    Index: pom.xml
    ===================================================================
    --- pom.xml (revision 1517)
    +++ pom.xml (working copy)
    @@ -118,6 +118,11 @@
    2.0


    + org.apache.maven
    + maven-core
    + 2.0
    +

    +
    junit
    junit
    4.8.1
    @@ -125,6 +130,12 @@
    test


    + commons-lang
    + commons-lang
    + 2.6
    + jar
    +

    +
    org.avaje
    ebean
    ${ebean.version}

 
woResponse

Upload a file