Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [eclipselink-users] NullPointerException in PersistenceObjectAttributeAccessor

Laird,

Can you also provide information about how your persistence unit and Entity caching is setup. What persistence unit properties are you using related to caching? Do you have caching options in orm.xml files? Are there caching annotations besides the ones in the source provided below?

-Tom

Christopher Delahunt wrote:
Hi Laird,

Can you catch the exception and try calling JPAHelper.getEntityManager(em).getServerSession().getIdentityMapAccessor().printIdentityMap(AnswerEntity.class) ? This will show what is in the shared cache for this class when the exception occurs. Also, can you turn logging on to finest? This will show the exact revision of EclipseLink being used (I'm not sure which was picked up by Glassfish 3.1b36), and the log might help track down how a null is getting into the cache though hopefully it is not needed. I believe it might be being nulled out due to garbage collection. If that is the case, a workaround might be to increase the size of the cache used for that object (assuming you are using a softCacheWeakIdentityMap), switch to a fullidentitymap, or set it to be isolated.
Best Regards,
Chris

On 10/01/2011 10:31 AM, Laird Nelson wrote:
(Oh, /not/ a simple bug; my mistake in my earlier response. Sorry; long day already and it's just begun.)

I've included a snippet of the code that builds and runs the query.

This use case is actually not necessarily all that strange. Imagine if you will a survey application where multiple choice answers are stored in tables, each of which has a structure like all the others. Let's say there's a table named HomelessShelters, and it has rows that name homeless shelters in the greater metro area. Each row has an ID ("7") and a text ("Pine Street Inn").

From these identically structured tables we can build up a set of Answer entities. An Answer entity is mapped like this:

@Entity(name = "Answer")
@IdClass(AnswerEntity.AnswerID.class)
@Table(name = "Answer")
public class AnswerEntity implements Answer {

  /**
   * The {@link NamedAnswerSet} to which this {@link AnswerEntity}
   * belongs.  This field may be {@code null} only at construction
   * time.
   */
@JoinColumn(insertable = false, name = "ANSWERSETNAME", nullable = false, updatable = false) // name must be uppercase for portability @ManyToOne(fetch = FetchType.EAGER, optional = false, targetEntity = NamedAnswerSetEntity.class)
  @NotNull
  NamedAnswerSet answerSet;
/**
   * The opaque and unique identifier for this {@link AnswerEntity}.
   */
  @Column(name = "ID") // name must be uppercase for portability
  @Id
  private int id;

@Column(name = "ANSWERSETNAME") // name must be uppercase for portability
  @Id
  @NotNull
  private String answerSetName;

  /**
   * The text describing this {@link AnswerEntity}.  This field may be
   * {@code null} only at construction time.
   */
  @Basic(optional = false)
@Column(length = 100, name = "TEXT", nullable = false) // name must be uppercase for portability
  @NotNull
  private String text;

  /**
   * A comma and/or whitespace-delimited {@link String} of identifiers
   * usually supplied by the {@link TableAnswerSetEntity} that built
   * this {@link AnswerEntity}.  An {@link AnswerEntity} will
   * typically sift through this {@link String} to see if its {@link
   * #getID() ID} is contained in it.
   *
   * @see #isFreeResponsePermitted()
   */
  @Column(name = "FREERESPONSEIDS", length = 255, updatable = false)
  private String freeResponseIds;

  /**
   * A {@link Boolean} representing the result of combing through the
   * {@link #freeResponseIds} field for our own {@link #getID() id}.
   *
   * @see #isFreeResponsePermitted()
   */
  @Transient
  private Boolean freeResponsePermitted;

}

Logically all AnswerEntities belong to AnswerSets. One kind of AnswerSet is one drawn from a table in the manner that I've described. Others include constrained numeric AnswerSets; still others are defined more or less out of thin air and backed by Drools, the JBoss rules engine. Short answer: build an AnswerEntity one way or another, and that's what you pick when you choose an answer to a multiple choice question.

So this query is concerned with constructing AnswerEntities out of particular kinds of tables.

Here is a snippet of code that builds and runs the query. I have not yet sanitized the inputs; obviously I need to guard against SQL injection here in a way that normally, using garden variety PreparedStatements, I wouldn't.

final String tableName = "HomelessShelters"; // real code obviously gets this from somewhere else final String answerSetName = this.getName(); // e.g. "HomelessSheltersAnswerSet"
assert answerSetName != null;
final String sql;
final StringBuilder sb = new StringBuilder("SELECT t.%s AS ID, '%s' AS ANSWERSETNAME, t.%s AS TEXT, %s AS FREERESPONSEIDS FROM %s t");
if (orderByColumnName != null) {
  sb.append(" ORDER BY %s");
sql = String.format(sb.toString(), this.getIDColumnName(), answerSetName, this.getTextColumnName(), this.freeResponseIds == null ? "NULL" : String.format("\"%s\"", this.freeResponseIds), tableName, orderByColumnName);
} else {
sql = String.format(sb.toString(), this.getIDColumnName(), answerSetName, this.getTextColumnName(), this.freeResponseIds == null ? "NULL" : String.format("\"%s\"", this.freeResponseIds), tableName);
}
*final Query q = em.createNativeQuery(sql, AnswerEntity.class);*
assert q != null;
@SuppressWarnings("unchecked")
final List<AnswerEntity> results = q.getResultList();
assert results != null;
for (final AnswerEntity a : results) {
  if (a != null) {
    a.setAnswerSet(this);
  }
}
returnValue = new LinkedHashSet<AnswerEntity>(results);

So nothing too odd going on here, I don't think, at least where the query is concerned.

Best,
Laird

On Mon, Jan 10, 2011 at 9:53 AM, Tom Ware <tom.ware@xxxxxxxxxx <mailto:tom.ware@xxxxxxxxxx>> wrote:

    You might want to look at how FreeResponse is mapped.  What is the
    @Id, is there a way a component of the @Id can be unexpectedly
    made null by the user.

    How is the query executed?  Is there a result set mapping?

    -Tom

    Laird Nelson wrote:

        I noticed that too; simple bug; should have been
        t.freeResponseIds.

        The query itself is actually dynamic and the table name is
        supplied at query build time.  The intent is to turn this
        native query into a set of entities, which works fine.

        (There is a set of tables in my application that are under the
        control of the user; they all share these fields in common.
         Through various gyrations of the app, the user can pick which
        table to build normalized entities out of; this native query
        gets assembled from the table name.  So a simple entity
        mapping doesn't work, because the table name is not known at
        compile/startup time.)

        I'll keep an eye on this and see if I can narrow down what I
        was doing when it happens again.  I cannot reproduce this in a
        unit test (I've tried, believe me).

        Best,
        Laird

        On Mon, Jan 10, 2011 at 9:39 AM, Tom Ware <tom.ware@xxxxxxxxxx
        <mailto:tom.ware@xxxxxxxxxx> <mailto:tom.ware@xxxxxxxxxx
        <mailto:tom.ware@xxxxxxxxxx>>> wrote:

           This exception seems to occur when trying to set a value in
        a null
           object.  I am not sure what would cause EclipseLink to try
        to do
           that.  Can you provide any other information about what is
        occuring?

           I notice that your example query selects "freeResponseIds"
        but does
           not link it to anything else in your query. (i.e. you
        select t.id <http://t.id>
           <http://t.id>, t.text with "t." but freeResponseIds without
        the

           "t.") What is the goal here?

           -Tom

           Laird Nelson wrote:

               I have an application that runs a simple JPA native
        query.  99
               out of 100 times the query works fine.  Then every now
        and again
               I get this:

               Caused by: java.lang.NullPointerException
                  at
org.eclipse.persistence.internal.descriptors.PersistenceObjectAttributeAccessor.setAttributeValueInObject(PersistenceObjectAttributeAccessor.java:46)
                  at
org.eclipse.persistence.mappings.DatabaseMapping.setAttributeValueInObject(DatabaseMapping.java:1426)
                  at
org.eclipse.persistence.mappings.DatabaseMapping.readFromRowIntoObject(DatabaseMapping.java:1317)
                  at
org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildAttributesIntoObject(ObjectBuilder.java:343)
                  at
org.eclipse.persistence.internal.descriptors.ObjectBuilder.refreshObjectIfRequired(ObjectBuilder.java:3333)
                  at
org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildWorkingCopyCloneFromRow(ObjectBuilder.java:1495)
                  at
org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObjectInUnitOfWork(ObjectBuilder.java:559)
                  at
org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:496)
                  at
org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:455)
                  at
org.eclipse.persistence.queries.ObjectLevelReadQuery.buildObject(ObjectLevelReadQuery.java:723)
                  at
org.eclipse.persistence.queries.ReadAllQuery.registerResultInUnitOfWork(ReadAllQuery.java:743)
                  at
org.eclipse.persistence.queries.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:424)
                  at
org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1080)
                  at
org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:808)
                  at
org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1040)
                  at
org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:384)
                  at
org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1126)
                  at
org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2904)
                  at
org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1508)
                  at
org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1490)
                  at
org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1464)
                  at
org.eclipse.persistence.internal.jpa.EJBQueryImpl.executeReadQuery(EJBQueryImpl.java:484)
                  at
org.eclipse.persistence.internal.jpa.EJBQueryImpl.getResultList(EJBQueryImpl.java:741)

               Once the query has failed in this manner, it will
        continue to
               fail until application restart.

               I am using the EclipseLink version that is bundled with
               Glassfish 3.1b36.

               My query is SELECT t.id <http://t.id> <http://t.id>
        <http://t.id> AS ID,

               'FreeResponse' AS ANSWERSETNAME, t.text AS TEXT,
        freeResponseIds
               AS FREERESPONSEIDS FROM FreeResponse t


               What is EclipseLink trying to tell me here?

               Thanks,
               Laird


------------------------------------------------------------------------

               _______________________________________________
               eclipselink-users mailing list
               eclipselink-users@xxxxxxxxxxx
        <mailto:eclipselink-users@xxxxxxxxxxx>
        <mailto:eclipselink-users@xxxxxxxxxxx
        <mailto:eclipselink-users@xxxxxxxxxxx>>

               https://dev.eclipse.org/mailman/listinfo/eclipselink-users

           _______________________________________________
           eclipselink-users mailing list
           eclipselink-users@xxxxxxxxxxx
        <mailto:eclipselink-users@xxxxxxxxxxx>
        <mailto:eclipselink-users@xxxxxxxxxxx
        <mailto:eclipselink-users@xxxxxxxxxxx>>

           https://dev.eclipse.org/mailman/listinfo/eclipselink-users



        ------------------------------------------------------------------------

        _______________________________________________
        eclipselink-users mailing list
        eclipselink-users@xxxxxxxxxxx
        <mailto:eclipselink-users@xxxxxxxxxxx>
        https://dev.eclipse.org/mailman/listinfo/eclipselink-users

    _______________________________________________
    eclipselink-users mailing list
    eclipselink-users@xxxxxxxxxxx <mailto:eclipselink-users@xxxxxxxxxxx>
    https://dev.eclipse.org/mailman/listinfo/eclipselink-users


------------------------------------------------------------------------

_______________________________________________
eclipselink-users mailing list
eclipselink-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/eclipselink-users

------------------------------------------------------------------------

_______________________________________________
eclipselink-users mailing list
eclipselink-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/eclipselink-users


Back to the top