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

NPE in APT Plugin (Processor.processEmbedded(..)) #27

Closed
popsteegh opened this Issue Oct 12, 2011 · 6 comments

Comments

Projects
None yet
2 participants
@popsteegh

When generating the query types using the Maven APT plugin, I get a NPE when processing an embedded entity in combination with generics (see stack trace below).

I have the following abstract base entity class:

@MappedSuperclass
public abstract class AbstractEntity<C extends EntityCode> implements Entity<AbstractEntity> {

    /**
     * The code of the entity, never null and unique per typed entity.
     */
    @Embedded
    @Column(name = "code", nullable = false, unique = true)
    protected C code;
}

The abstract base entity class has a member of type EntityCode, which is a base class for all different types of entity codes and is embeddable:

@MappedSuperclass
public class EntityCode implements ValueObject<EntityCode> {

    @Column(name = "code", unique = true)
    private String code;

    // Default no-arg constructor needed for JPA
    protected EntityCode() {
    }

    public EntityCode(String code) {
        Validate.notNull(code, "code is null");
        this.code = code;
    }
}

Now when generating the query type for an entity class that extends the base entity AbstractEntity, I get the following NPE:

An annotation processor threw an uncaught exception.
Consult the following stack trace for details.
java.lang.NullPointerException
    at com.mysema.query.apt.Processor.processEmbedded(Processor.java:641)
    at com.mysema.query.apt.Processor.processAnnotations(Processor.java:161)
    at com.mysema.query.apt.Processor.process(Processor.java:128)
    at com.mysema.query.apt.jpa.JPAAnnotationProcessor.process(JPAAnnotationProcessor.java:48)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:625)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:554)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:699)
    at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:981)
    at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:727)
    at com.sun.tools.javac.main.Main.compile(Main.java:353)
    at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:115)
    at com.mysema.maven.apt.AbstractProcessorMojo.execute(AbstractProcessorMojo.java:210)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:107)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:209)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:319)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:156)
    at org.apache.maven.cli.MavenCli.execute(MavenCli.java:534)
    at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:196)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:141)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:290)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:230)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:409)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:352)
    at org.codehaus.classworlds.Launcher.main(Launcher.java:47)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

Could somebody please investigate this issue? Please let me know if you need anything else or whether I can be of any assistance.

Cheers,
Pepijn

timowest added a commit that referenced this issue Oct 12, 2011

@popsteegh

This comment has been minimized.

Show comment
Hide comment
@popsteegh

popsteegh Oct 13, 2011

Thanks Timo, for your quick response!

I have given your fix a try (made a build for 2.2.3.SNAPSHOT-BUILD) however the Processor now generates code that tries to directly instantiate the "Path" interface:

/**
 * QBrand is a Querydsl query type for Brand
 */
@Generated("com.mysema.query.codegen.EntitySerializer")
public class QBrand extends EntityPathBase<Brand> {

    public static final QBrand brand = new QBrand("brand");

    public final com.essentialmall.business.domain.common.QAbstractNamedEntity _super;

    // custom
    public final Path<BrandCode> code = new Path(forProperty("code"));

The code above is a snippet from the generated query type QBrand for the entity Brand.

Obviously, this code doesn't compile. Could you please have another look into this?

Cheers,
Pepijn

Thanks Timo, for your quick response!

I have given your fix a try (made a build for 2.2.3.SNAPSHOT-BUILD) however the Processor now generates code that tries to directly instantiate the "Path" interface:

/**
 * QBrand is a Querydsl query type for Brand
 */
@Generated("com.mysema.query.codegen.EntitySerializer")
public class QBrand extends EntityPathBase<Brand> {

    public static final QBrand brand = new QBrand("brand");

    public final com.essentialmall.business.domain.common.QAbstractNamedEntity _super;

    // custom
    public final Path<BrandCode> code = new Path(forProperty("code"));

The code above is a snippet from the generated query type QBrand for the entity Brand.

Obviously, this code doesn't compile. Could you please have another look into this?

Cheers,
Pepijn

@timowest

This comment has been minimized.

Show comment
Hide comment
@timowest

timowest Oct 13, 2011

Member

Can you give me a better view on your domain model? How does Brand and related classes look like?

Member

timowest commented Oct 13, 2011

Can you give me a better view on your domain model? How does Brand and related classes look like?

@popsteegh

This comment has been minimized.

Show comment
Hide comment
@popsteegh

popsteegh Oct 13, 2011

Timo,

The Brand class looks like this:

@javax.persistence.Entity
@Table(name="brand")
public class Brand extends AbstractNamedEntity<BrandCode> {

    private static final Logger LOGGER = LoggerFactory.getLogger(Brand.class);

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "brand_id")
    private Long id;

    ...
    ...
}

Brand extends AbstractNamedEntity which extends AbstractMultilingualEntity:

@MappedSuperclass
public abstract class AbstractNamedEntity<C extends EntityCode> extends AbstractMultilingualEntity<C> {

    @Column(name = "name_en", nullable = false)
    protected String nameEn;

    @Column(name = "name_nl")
    protected String nameNl;

    protected AbstractNamedEntity() {
        super();
    }

    protected AbstractNamedEntity(C code) {
        super(code);
    }

    ...
    ...
}

and:

public class AbstractMultilingualEntity<C extends EntityCode> extends AbstractEntity<C> {

    public AbstractMultilingualEntity() {
    }

    public AbstractMultilingualEntity(C code) {
        super(code);
    }

    ...
    ...
}

AbstractMultilingual class extends AbstractEntity which has already been given previously. AbstractEntity implements the Entity interface:

public interface Entity<T> extends Serializable {

    /**
     * Entities compare by identity, not by attributes.
     *
     * @param other The other entity.
     * @return true if the identities are the same, regardless of other attributes.
     */
    boolean sameIdentityAs(T other);

    ...
    ...
}

The BrandCode class looks like this:

public class BrandCode extends EntityCode {

    // Default no-arg constructor needed for JPA
    public BrandCode() {
    }

    public BrandCode(String code) {
        super(code);
    }

    ...
    ...
}

The BrandCode class extends the abstract EntityCode class which was also already given previously (see issue description). Obviously, I have left out all unimportant members and methods from the classes given above.

Basically, the given classes are all part of two class hierarchies: one for entity codes (1) and one for entities (2):

  1. BrandCode extends EntityCode
  2. Brand extends AbstractNamedEntity which extends AbstractMultilingualEntity which extends AbstractEntity which implements interface Entity

Nothing special really. Hope this help to figure out what is going on here....

Cheers,
Pepijn

Timo,

The Brand class looks like this:

@javax.persistence.Entity
@Table(name="brand")
public class Brand extends AbstractNamedEntity<BrandCode> {

    private static final Logger LOGGER = LoggerFactory.getLogger(Brand.class);

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "brand_id")
    private Long id;

    ...
    ...
}

Brand extends AbstractNamedEntity which extends AbstractMultilingualEntity:

@MappedSuperclass
public abstract class AbstractNamedEntity<C extends EntityCode> extends AbstractMultilingualEntity<C> {

    @Column(name = "name_en", nullable = false)
    protected String nameEn;

    @Column(name = "name_nl")
    protected String nameNl;

    protected AbstractNamedEntity() {
        super();
    }

    protected AbstractNamedEntity(C code) {
        super(code);
    }

    ...
    ...
}

and:

public class AbstractMultilingualEntity<C extends EntityCode> extends AbstractEntity<C> {

    public AbstractMultilingualEntity() {
    }

    public AbstractMultilingualEntity(C code) {
        super(code);
    }

    ...
    ...
}

AbstractMultilingual class extends AbstractEntity which has already been given previously. AbstractEntity implements the Entity interface:

public interface Entity<T> extends Serializable {

    /**
     * Entities compare by identity, not by attributes.
     *
     * @param other The other entity.
     * @return true if the identities are the same, regardless of other attributes.
     */
    boolean sameIdentityAs(T other);

    ...
    ...
}

The BrandCode class looks like this:

public class BrandCode extends EntityCode {

    // Default no-arg constructor needed for JPA
    public BrandCode() {
    }

    public BrandCode(String code) {
        super(code);
    }

    ...
    ...
}

The BrandCode class extends the abstract EntityCode class which was also already given previously (see issue description). Obviously, I have left out all unimportant members and methods from the classes given above.

Basically, the given classes are all part of two class hierarchies: one for entity codes (1) and one for entities (2):

  1. BrandCode extends EntityCode
  2. Brand extends AbstractNamedEntity which extends AbstractMultilingualEntity which extends AbstractEntity which implements interface Entity

Nothing special really. Hope this help to figure out what is going on here....

Cheers,
Pepijn

@timowest

This comment has been minimized.

Show comment
Hide comment
@timowest

timowest Oct 13, 2011

Member

A temporary fix is to annotate BrandCode with @Embeddable. I will figure out a proper fix.

Member

timowest commented Oct 13, 2011

A temporary fix is to annotate BrandCode with @Embeddable. I will figure out a proper fix.

@popsteegh

This comment has been minimized.

Show comment
Hide comment
@popsteegh

popsteegh Oct 14, 2011

Ok, that has fixed it for now. Thanks for that! Looking forward to a structural solution.

Ok, that has fixed it for now. Thanks for that! Looking forward to a structural solution.

@timowest

This comment has been minimized.

Show comment
Hide comment
@timowest

timowest Nov 19, 2011

Member

Released in 2.2.5

Member

timowest commented Nov 19, 2011

Released in 2.2.5

@timowest timowest closed this Nov 19, 2011

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment