0

我将其追溯到将空数据存储类返回给 createPerImplementationColumnsForReferenceField 的 getDatastoreClass。

我已经尝试了 3.1.1 和现在使用 3.2.0-m4 版本,希望能解决我的问题。

RDBMSStoreManager#getDatastoreClass(String className, ClassLoaderResolver clr);

它正在向

ReferenceMapping#createPerImplementationColumnsForReferenceField(boolean pk, boolean nullable, boolean serialised, boolean embedded, int fieldRole, ColumnMetaData[] columnMetaData, ClassLoaderResolver clr)

我正在使用 orm 来注释映射超类,而这个映射超类没有表定义,并且我的两个映射超类都抛出了这个异常。

499170 [http-bio-8080-exec-8] DEBUG DataNucleus.Datastore.Schema  - Field [com.hp.vf.server.domain.AlertDefinition.isPublic] -> Column(s) ["ALERTDEFINITION"."ISPUBLIC"] using mapping of type "org.datanucleus.store.rdbms.mapping.java.BooleanMapping" (org.datanucleus.store.rdbms.mapping.datastore.SmallIntRDBMSMapping)
551964 [http-bio-8080-exec-8] DEBUG DataNucleus.Persistence  - Managing Persistence of Class : com.hp.vf.analytics.shared.metric.Metric [Table : (none), InheritanceStrategy : subclass-table]
561964 [http-bio-8080-exec-8] ERROR DataNucleus.Datastore.Schema  - An exception was thrown while adding/validating class(es) : null
java.lang.NullPointerException
    at org.datanucleus.store.rdbms.mapping.java.ReferenceMapping.createPerImplementationColumnsForReferenceField(ReferenceMapping.java:452)
    at org.datanucleus.store.rdbms.mapping.java.ReferenceMapping.prepareDatastoreMapping(ReferenceMapping.java:214)
    at org.datanucleus.store.rdbms.mapping.java.ReferenceMapping.initialize(ReferenceMapping.java:110)
    at org.datanucleus.store.rdbms.mapping.java.InterfaceMapping.initialize(InterfaceMapping.java:54)

在参考映射中,尝试执行 getIdMapping() 时 dc 为空,我已在调试器中验证了这一点。

           try
            {
                DatastoreClass dc = storeMgr.getDatastoreClass(implClass.getName(), clr);
                m = dc.getIdMapping(); // DC is null 
            }
            catch (NoTableManagedException ex)
            {
                // TODO Localise this message
                throw new NucleusUserException("Cannot define columns for " + mmd.getFullFieldName() + 
                    " due to " + ex.getMessage(), ex);
            }

这是有问题的类文件。

public abstract class Metric implements IMetric {

    /**
     * Serialization ID
     */
    private static final long serialVersionUID = 3806479436166940035L;

    private Long id;

    /**
     * The name of the metric, this is not mandatory we have some metrics that
     * may come back without names.
     */
    protected String name;

    /**
     * This is an optional metric value that can be set by the script in order
     * to add context to the execution of the metric.
     */
    protected String context;

    /**
     * The list of violations associated with this metric.
     */
    protected List<Violation> violations = null;

    public Metric() {
        violations = new ArrayList<Violation>();
    }

    /**
     * Constructor that takes the name of the object and the value that it
     * represents.
     * 
     * @param name
     * @param value
     */
    public Metric(String name) {
        this();
        this.name = name;
    }

    /* (non-Javadoc)
     * @see com.hp.vf.taskengine.shared.metric.IMetric#getName()
     */
    @Override
    public String getName() {
        return name;
    }

    /* (non-Javadoc)
     * @see com.hp.vf.taskengine.shared.metric.IMetric#setName(java.lang.String)
     */
    @Override
    public void setName(String name) {
        this.name = name;
    }

    /**
     * This is the context that represents the metric. This could have come from
     * R and would be a Key:Value; pair of values used to calculate the value.
     * For example if a metric was calculated for a product in houston for ISS
     * the context may look like "ProdNum:1234;Factory:Houston;BUnit:ISS". This
     * context is useful when chaining together tasks.
     * 
     * @return String context used when chaining tasks together.
     */
    public String getContext() {
        return context;
    }

    /* (non-Javadoc)
     * @see com.hp.vf.taskengine.shared.metric.IMetric#toString()
     */
    public String toString() {
        String debugString = "";
        debugString += "Metric: " + name;

        return debugString;
    }

    /* (non-Javadoc)
     * @see com.hp.vf.taskengine.shared.metric.IMetric#hasMetricViolations()
     */
    @Override
    public boolean hasMetricViolations() {
        return (violations != null && violations.size() > 0) ? true : false;
    }


    /* (non-Javadoc)
     * @see com.hp.vf.taskengine.shared.metric.IMetric#getViolations()
     */
    @Override
    public List<IViolation> getViolations() {
        return violations;
    }

    /* (non-Javadoc)
     * @see com.hp.vf.taskengine.shared.metric.IMetric#setViolations(java.util.List)
     */
    @Override
    public void setViolations(List<IViolation> violations) {
        this.violations = violations;
    }

    @Override
    public Long getId() {
        return id;
    }
}

这是我的 orm.xml 文件的摘录

<access>FIELD</access>

<mapped-superclass class="com.hp.vf.analytics.shared.metric.Metric" access="FIELD">
    <attributes>
        <basic name="name" />
        <basic name="context" />
        <one-to-many name="violations">
            <cascade>
                <cascade-all />
            </cascade>
        </one-to-many>
    </attributes>
</mapped-superclass>

我做错了什么还是这是一个错误?

4

1 回答 1

0

我能够使用 Datanucleus 的提示解决问题。我有多个问题

问题
对我来说最明显和最愚蠢的

如果您有一个使用接口的一对多或一对一,您必须指定目标实体。

    /**
     * The list of violations associated with this metric.
     */
    protected List<IViolation> violations = null;
...
    <one-to-many name="violations"
      target-entity="com.vf.analytics.shared.metric.Violation">
       <cascade>
          <cascade-all />
       </cascade>
    </one-to-many>

不要使用泛型,jpa 规范不支持它们
不确定 datanucleus 是否支持泛型,但可能不推荐。

public MetricNumber< T extends Number> extends Metric implements IMetric {
  T value;
}

如果您扩展一个未注释的实体,请确保将其添加到您的 orm.xml

我没有测试某些对象,所以我认为 datanucleus 会忽略它们,但事实并非如此。我扩展了未注释但尚未将它们添加到 orm.xml 的第三方类,这也导致我得到的空指针异常为 null。

于 2013-02-27T14:31:36.823 回答