@Override public DatastoreTable getDatastoreClass(String className, ClassLoaderResolver clr) { try { // We see the occasional race condition when multiple threads concurrently // perform an operation using a persistence-capable class for which DataNucleus // has not yet generated the meta-data. The result is usually // AbstractMemberMetaData objects with the same column listed twice in the meta-data. // Locking at this level is a bit more coarse-grained than I'd like but once the // meta-data has been built this will return super fast so it shouldn't be an issue. synchronized (this) { return (DatastoreTable) super.getDatastoreClass(className, clr); } } catch (NoTableManagedException e) { // Our parent class throws this when the class isn't PersistenceCapable also. Class cls = clr.classForName(className); ApiAdapter api = getApiAdapter(); if (cls != null && !cls.isInterface() && !api.isPersistable(cls)) { throw new NoTableManagedException( "Class " + className + " does not seem to have been enhanced. You may want to rerun " + "the enhancer and check for errors in the output."); // Suggest you address why this method is being called before any check on whether it is // persistable // then you can remove this error message } throw e; } }
/** * Method to populate any defaults, and check the validity of the MetaData. * * @param clr ClassLoaderResolver to use for loading any key/value types * @param primary the primary ClassLoader to use (or null) * @param mmgr MetaData manager */ public void populate(ClassLoaderResolver clr, ClassLoader primary, MetaDataManager mmgr) { AbstractMemberMetaData mmd = (AbstractMemberMetaData) parent; if (!StringUtils.isWhitespace(key.type) && key.type.indexOf(',') > 0) { throw new InvalidMetaDataException(LOCALISER, "044143", mmd.getName(), mmd.getClassName()); } if (!StringUtils.isWhitespace(value.type) && value.type.indexOf(',') > 0) { throw new InvalidMetaDataException(LOCALISER, "044144", mmd.getName(), mmd.getClassName()); } ApiAdapter api = mmgr.getApiAdapter(); // Make sure the type in "key", "value" is set key.populate( ((AbstractMemberMetaData) parent).getAbstractClassMetaData().getPackageName(), clr, primary, mmgr); value.populate( ((AbstractMemberMetaData) parent).getAbstractClassMetaData().getPackageName(), clr, primary, mmgr); // Check the field type and see if it is castable to a Map Class field_type = getMemberMetaData().getType(); if (!java.util.Map.class.isAssignableFrom(field_type)) { throw new InvalidMetaDataException( LOCALISER, "044145", getFieldName(), getMemberMetaData().getClassName(false)); } if (java.util.Properties.class.isAssignableFrom(field_type)) { // Properties defaults to <String, String> if (key.type == null) { key.type = String.class.getName(); } if (value.type == null) { value.type = String.class.getName(); } } // "key-type" if (key.type == null) { throw new InvalidMetaDataException( LOCALISER, "044146", getFieldName(), getMemberMetaData().getClassName(false)); } // Check that the key type exists Class keyTypeClass = null; try { keyTypeClass = clr.classForName(key.type, primary); } catch (ClassNotResolvedException cnre) { try { // Maybe the user specified a java.lang class without fully-qualifying it // This is beyond the scope of the JDO spec which expects java.lang cases to be // fully-qualified keyTypeClass = clr.classForName(ClassUtils.getJavaLangClassForType(key.type), primary); } catch (ClassNotResolvedException cnre2) { throw new InvalidMetaDataException( LOCALISER, "044147", getFieldName(), getMemberMetaData().getClassName(false), key.type); } } if (!keyTypeClass.getName().equals(key.type)) { // The value-type has been resolved from what was specified in the MetaData - update to the // fully-qualified name NucleusLogger.METADATA.info( LOCALISER.msg( "044148", getFieldName(), getMemberMetaData().getClassName(false), key.type, keyTypeClass.getName())); key.type = keyTypeClass.getName(); } // "embedded-key" if (key.embedded == null) { // Assign default for "embedded-key" based on 18.13.2 of JDO 2 spec if (mmgr.getNucleusContext().getTypeManager().isDefaultEmbeddedType(keyTypeClass)) { key.embedded = Boolean.TRUE; } else if (api.isPersistable(keyTypeClass) || Object.class.isAssignableFrom(keyTypeClass) || keyTypeClass.isInterface()) { key.embedded = Boolean.FALSE; } else { key.embedded = Boolean.TRUE; } } if (Boolean.FALSE.equals(key.embedded)) { // If the user has set a non-PC/non-Interface as not embedded, correct it since not supported. // Note : this fails when using in the enhancer since not yet PC if (!api.isPersistable(keyTypeClass) && !keyTypeClass.isInterface() && keyTypeClass != java.lang.Object.class) { key.embedded = Boolean.TRUE; } } KeyMetaData keymd = ((AbstractMemberMetaData) parent).getKeyMetaData(); if (keymd != null && keymd.getEmbeddedMetaData() != null) { // If the user has specified <embedded>, set to true key.embedded = Boolean.TRUE; } // "value-type" if (value.type == null) { throw new InvalidMetaDataException( LOCALISER, "044149", getFieldName(), getMemberMetaData().getClassName(false)); } // Check that the value-type exists Class valueTypeClass = null; try { valueTypeClass = clr.classForName(value.type); } catch (ClassNotResolvedException cnre) { try { // Maybe the user specified a java.lang class without fully-qualifying it // This is beyond the scope of the JDO spec which expects java.lang cases to be // fully-qualified valueTypeClass = clr.classForName(ClassUtils.getJavaLangClassForType(value.type)); } catch (ClassNotResolvedException cnre2) { throw new InvalidMetaDataException( LOCALISER, "044150", getFieldName(), getMemberMetaData().getClassName(false), value.type); } } if (!valueTypeClass.getName().equals(value.type)) { // The value-type has been resolved from what was specified in the MetaData - update to the // fully-qualified name NucleusLogger.METADATA.info( LOCALISER.msg( "044151", getFieldName(), getMemberMetaData().getClassName(false), value.type, valueTypeClass.getName())); value.type = valueTypeClass.getName(); } // "embedded-value" if (value.embedded == null) { // Assign default for "embedded-value" based on 18.13.2 of JDO 2 spec if (mmgr.getNucleusContext().getTypeManager().isDefaultEmbeddedType(valueTypeClass)) { value.embedded = Boolean.TRUE; } else if (api.isPersistable(valueTypeClass) || Object.class.isAssignableFrom(valueTypeClass) || valueTypeClass.isInterface()) { value.embedded = Boolean.FALSE; } else { value.embedded = Boolean.TRUE; } } if (value.embedded == Boolean.FALSE) { // If the user has set a non-PC/non-Interface as not embedded, correct it since not supported. // Note : this fails when using in the enhancer since not yet PC if (!api.isPersistable(valueTypeClass) && !valueTypeClass.isInterface() && valueTypeClass != java.lang.Object.class) { value.embedded = Boolean.TRUE; } } ValueMetaData valuemd = ((AbstractMemberMetaData) parent).getValueMetaData(); if (valuemd != null && valuemd.getEmbeddedMetaData() != null) { // If the user has specified <embedded>, set to true value.embedded = Boolean.TRUE; } key.classMetaData = mmgr.getMetaDataForClassInternal(keyTypeClass, clr); value.classMetaData = mmgr.getMetaDataForClassInternal(valueTypeClass, clr); // Cater for Key with mapped-by needing to be PK (for JPA) if (keymd != null && keymd.mappedBy != null && keymd.mappedBy.equals("#PK")) // Special value set by JPAMetaDataHandler { // Need to set the mapped-by of <key> to be the PK of the <value> if (value.classMetaData.getNoOfPrimaryKeyMembers() != 1) { // TODO Localise this throw new NucleusUserException( "DataNucleus does not support use of <map-key> with no name field when the" + " value class has a composite primary key"); } int[] valuePkFieldNums = value.classMetaData.getPKMemberPositions(); keymd.mappedBy = value.classMetaData.getMetaDataForManagedMemberAtAbsolutePosition(valuePkFieldNums[0]) .name; } // Make sure anything in the superclass is populated too super.populate(clr, primary, mmgr); setPopulated(); }
/** * Method to populate any defaults, and check the validity of the MetaData. * * @param clr ClassLoaderResolver to use for any loading operations * @param primary the primary ClassLoader to use (or null) * @param mmgr MetaData manager */ public void populate(ClassLoaderResolver clr, ClassLoader primary, MetaDataManager mmgr) { AbstractMemberMetaData mmd = (AbstractMemberMetaData) parent; if (!StringUtils.isWhitespace(element.type) && element.type.indexOf(',') > 0) { throw new InvalidMetaDataException(LOCALISER, "044131", mmd.getName(), mmd.getClassName()); } // Make sure the type in "element" is set element.populate( ((AbstractMemberMetaData) parent).getAbstractClassMetaData().getPackageName(), clr, primary, mmgr); // Check the field type and see if it is castable to a Collection Class field_type = getMemberMetaData().getType(); if (!java.util.Collection.class.isAssignableFrom(field_type)) { throw new InvalidMetaDataException( LOCALISER, "044132", getFieldName(), getMemberMetaData().getClassName(false)); } // "element-type" if (element.type == null) { throw new InvalidMetaDataException( LOCALISER, "044133", getFieldName(), getMemberMetaData().getClassName(false)); } // Check that the element type exists Class elementTypeClass = null; try { elementTypeClass = clr.classForName(element.type, primary); } catch (ClassNotResolvedException cnre) { throw new InvalidMetaDataException( LOCALISER, "044134", getFieldName(), getMemberMetaData().getClassName(false), element.type); } if (!elementTypeClass.getName().equals(element.type)) { // The element-type has been resolved from what was specified in the MetaData - update to the // fully-qualified name NucleusLogger.METADATA.info( LOCALISER.msg( "044135", getFieldName(), getMemberMetaData().getClassName(false), element.type, elementTypeClass.getName())); element.type = elementTypeClass.getName(); } // "embedded-element" ApiAdapter api = mmgr.getApiAdapter(); if (element.embedded == null) { // Assign default for "embedded-element" based on 18.13.1 of JDO 2 spec // Note : this fails when using in the enhancer since not yet PC if (mmgr.getNucleusContext().getTypeManager().isDefaultEmbeddedType(elementTypeClass)) { element.embedded = Boolean.TRUE; } else if (api.isPersistable(elementTypeClass) || Object.class.isAssignableFrom(elementTypeClass) || elementTypeClass.isInterface()) { element.embedded = Boolean.FALSE; } else { element.embedded = Boolean.TRUE; } } if (Boolean.FALSE.equals(element.embedded)) { // If the user has set a non-PC/non-Interface as not embedded, correct it since not supported. // Note : this fails when using in the enhancer since not yet PC if (!api.isPersistable(elementTypeClass) && !elementTypeClass.isInterface() && elementTypeClass != java.lang.Object.class) { element.embedded = Boolean.TRUE; } } ElementMetaData elemmd = ((AbstractMemberMetaData) parent).getElementMetaData(); if (elemmd != null && elemmd.getEmbeddedMetaData() != null) { element.embedded = Boolean.TRUE; } if (Boolean.TRUE.equals(element.dependent)) { // If the user has set a non-PC/non-reference as dependent, correct it since not valid. // Note : this fails when using in the enhancer since not yet PC if (!api.isPersistable(elementTypeClass) && !elementTypeClass.isInterface() && elementTypeClass != java.lang.Object.class) { element.dependent = Boolean.FALSE; } } // Keep a reference to the MetaData for the element element.classMetaData = mmgr.getMetaDataForClassInternal(elementTypeClass, clr); // Make sure anything in the superclass is populated too super.populate(clr, primary, mmgr); setPopulated(); }