public Object getObject(final ExecutionContext ec, final Object rs)
{
// Find the class of the returned object in this row of the ResultSet
String className = null;
boolean requiresInheritanceCheck = true;
StatementMappingIndex discrimMapIdx = stmtMapping.getMappingForMemberPosition(StatementClassMapping.MEMBER_DISCRIMINATOR);
if (discrimMapIdx != null)
{
// Discriminator mapping registered so use that
try
{
String discrimValue = ((ResultSet)rs).getString(discrimMapIdx.getColumnPositions()[0]);
if (discrimValue == null)
{
// Discriminator has no value so return null object
NucleusLogger.DATASTORE_RETRIEVE.debug("Value of discriminator is null so assuming object is null");
return null;
}
JavaTypeMapping discrimMapping = discrimMapIdx.getMapping();
DiscriminatorMetaData dismd =
(discrimMapping != null ? discrimMapping.getDatastoreContainer().getDiscriminatorMetaData() : null);
className = MetaDataUtils.getClassNameFromDiscriminatorValue(discrimValue, dismd, ec);
}
catch (SQLException sqle)
{
NucleusLogger.DATASTORE_RETRIEVE.debug("Exception obtaining value of discriminator : " + sqle.getMessage());
}
}
else if (stmtMapping.getNucleusTypeColumnName() != null)
{
// Extract the object type using the NucleusType column (if available)
try
{
className = ((ResultSet)rs).getString(stmtMapping.getNucleusTypeColumnName()).trim();
if (className == null)
{
// Discriminator has no value so return null object
NucleusLogger.DATASTORE_RETRIEVE.debug("Value of determiner column is null so assuming object is null");
return null;
}
}
catch (SQLException sqle)
{
// NucleusType column not found so ignore
}
}
ClassLoaderResolver clr = ec.getClassLoaderResolver();
Class pcClassForObject = persistentClass;
if (className != null)
{
Class cls = (Class) resolvedClasses.get(className);
if (cls != null)
{
pcClassForObject = cls;
}
else
{
if (persistentClass.getName().equals(className))
{
pcClassForObject = persistentClass;
}
else
{
pcClassForObject = clr.classForName(className, persistentClass.getClassLoader());
}
resolvedClasses.put(className, pcClassForObject);
}
requiresInheritanceCheck = false;
}
String warnMsg = null;
if (Modifier.isAbstract(pcClassForObject.getModifiers()))
{
// Persistent class is abstract so we can't create instances of that type!
// This can happen if the user is using subclass-table and hasn't provided a discriminator in
// the table. Try going out one level and find a (single) concrete subclass
// TODO make this more robust and go out further
String[] subclasses = ec.getMetaDataManager().getSubclassesForClass(pcClassForObject.getName(), false);
if (subclasses != null)
{
Class concreteSubclass = null;
int numConcreteSubclasses = 0;
for (int i=0;i<subclasses.length;i++)
{
Class subcls = clr.classForName(subclasses[i]);
if (!Modifier.isAbstract(subcls.getModifiers()))
{
numConcreteSubclasses++;
concreteSubclass = subcls;
}
}
if (numConcreteSubclasses == 1)
{
// Only one possible subclass, so use that
pcClassForObject = concreteSubclass;
NucleusLogger.DATASTORE_RETRIEVE.warn(LOCALISER.msg("052300",
pcClassForObject.getName(), concreteSubclass.getName()));
}
else if (numConcreteSubclasses == 0)
{
throw new NucleusUserException(LOCALISER.msg("052301", pcClassForObject.getName()));
}
else
{
// More than 1 possible so notify the user. Really should return the abstract
warnMsg = "Found type=" + pcClassForObject +
" but abstract and more than 1 concrete subclass (" +
StringUtils.objectArrayToString(subclasses) + "). Really you need a discriminator " +
" to help identifying the type. Choosing " + concreteSubclass;
pcClassForObject = concreteSubclass;
requiresInheritanceCheck = true;
}
}
}
// Find the statement mappings and field numbers to use for the result class
// Caters for persistent-interfaces and the result class being an implementation
AbstractClassMetaData cmd = ec.getMetaDataManager().getMetaDataForClass(pcClassForObject, clr);
if (cmd == null)
{
// No way of identifying the object type so assumed to be null
// This can happen when selecting a class and also a related class via LEFT OUTER JOIN
// and the LEFT OUTER JOIN results in no related object, hence null discriminator etc
// TODO Improve this and check PK cols
return null;
}
int[] fieldNumbers = stmtMapping.getMemberNumbers();
StatementClassMapping mappingDefinition;
int[] mappedFieldNumbers;
if (acmd instanceof InterfaceMetaData)
{
// Persistent-interface : create new mapping definition for a result type of the implementation
mappingDefinition = new StatementClassMapping();
mappingDefinition.setNucleusTypeColumnName(stmtMapping.getNucleusTypeColumnName());
mappedFieldNumbers = new int[fieldNumbers.length];
for (int i = 0; i < fieldNumbers.length; i++)
{
AbstractMemberMetaData mmd = acmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumbers[i]);
mappedFieldNumbers[i] = cmd.getAbsolutePositionOfMember(mmd.getName());
mappingDefinition.addMappingForMember(mappedFieldNumbers[i],
stmtMapping.getMappingForMemberPosition(fieldNumbers[i]));
}
}
else
{
// Persistent class
mappingDefinition = stmtMapping;
mappedFieldNumbers = fieldNumbers;
}
// Extract any surrogate version
VersionMetaData vermd = cmd.getVersionMetaDataForClass();
Object surrogateVersion = null;
StatementMappingIndex versionMapping = null;
if (vermd != null)
{
if (vermd.getFieldName() == null)
{
versionMapping = stmtMapping.getMappingForMemberPosition(StatementClassMapping.MEMBER_VERSION);
}
else
{
AbstractMemberMetaData vermmd = cmd.getMetaDataForMember(vermd.getFieldName());
versionMapping = stmtMapping.getMappingForMemberPosition(vermmd.getAbsoluteFieldNumber());
}
}
if (versionMapping != null)
{
// Surrogate version column returned by query
JavaTypeMapping mapping = versionMapping.getMapping();
surrogateVersion = mapping.getObject(ec, rs, versionMapping.getColumnPositions());
}
// Extract the object from the ResultSet
Object obj = null;
boolean needToSetVersion = false;
if (persistentClass.isInterface() && !cmd.isImplementationOfPersistentDefinition())
{
// Querying by interface, and not a generated implementation so use the metadata for the interface
cmd = ec.getMetaDataManager().getMetaDataForInterface(persistentClass, clr);
}
if (cmd.getIdentityType() == IdentityType.APPLICATION)
{
// Check if the PK field(s) are all null (implies null object, when using OUTER JOIN)
int[] pkNumbers = cmd.getPKMemberPositions();
ResultSet resultSet = (ResultSet)rs;
boolean nullObject = true;
for (int i=0;i<pkNumbers.length;i++)
{
StatementMappingIndex pkIdx = mappingDefinition.getMappingForMemberPosition(pkNumbers[i]);
if (pkIdx == null)
{
throw new NucleusException("You have just executed an SQL statement yet the information " +
"for the primary key column(s) is not available! " +
"Please generate a testcase and report this issue");
}
int[] colPositions = pkIdx.getColumnPositions();
for (int j=0;j<colPositions.length;j++)
{
try
{
Object pkObj = resultSet.getObject(colPositions[j]);
if (pkObj != null)
{
nullObject = false;
break;
}
}
catch (SQLException sqle)
{
NucleusLogger.DATASTORE_RETRIEVE.warn("Exception thrown while retrieving results ", sqle);
}
if (!nullObject)
{
break;
}
}
}
if (nullObject)
{
obj = null;
}
else
{
// Retrieve the object with this application-identity
if (warnMsg != null)
{
NucleusLogger.DATASTORE_RETRIEVE.warn(warnMsg);
}
obj = getObjectForApplicationId(ec, rs, mappingDefinition, mappedFieldNumbers,
pcClassForObject, cmd, requiresInheritanceCheck, surrogateVersion);
}
}
else if (cmd.getIdentityType() == IdentityType.DATASTORE)
{
// Generate the "oid" for this object (of type pcClassForObject), and find the object for that
StatementMappingIndex datastoreIdMapping =
stmtMapping.getMappingForMemberPosition(StatementClassMapping.MEMBER_DATASTORE_ID);
JavaTypeMapping mapping = datastoreIdMapping.getMapping();
OID oid = (OID)mapping.getObject(ec, rs, datastoreIdMapping.getColumnPositions());
if (oid != null)
{
Object id = oid;
if (!pcClassForObject.getName().equals(oid.getPcClass()))
{