package com.breeze.hib;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.hibernate.*;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.id.Assigned;
import org.hibernate.id.ForeignGenerator;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.IdentityGenerator;
import org.hibernate.mapping.*;
import org.hibernate.metadata.*;
import org.hibernate.persister.collection.AbstractCollectionPersister;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.service.internal.SessionFactoryServiceRegistryImpl;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.type.*;
import com.breeze.metadata.Metadata;
import com.breeze.metadata.RawMetadata;
/**
* Builds a data structure containing the metadata required by Breeze.
*
* @see <a href="http://breeze.github.io/doc-js/metadata-schema.html">Breeze Metadata Doc</a>
* @author IdeaBlade
*
*/
@SuppressWarnings("rawtypes")
public class HibernateMetadata extends Metadata {
private SessionFactory _sessionFactory;
private Configuration _configuration;
private RawMetadata _rawMetadata;
private List<HashMap<String, Object>> _typeList;
private HashMap<String, Object> _resourceMap;
private HashSet<String> _typeNames;
private HashMap<String, String> _fkMap;
public HibernateMetadata(SessionFactory sessionFactory, Configuration configuration) {
_sessionFactory = sessionFactory;
_configuration = configuration;
}
public HibernateMetadata(SessionFactory sessionFactory) {
_sessionFactory = sessionFactory;
_configuration = getConfigurationFromRegistry(sessionFactory);
}
/**
* Build the raw Breeze metadata. This will then get wrapped with a strongly typed wrapper. The internal
* rawMetadata can be converted to JSON and sent to the Breeze client.
*/
@Override
public RawMetadata buildRawMetadata() {
initMap();
Map<String, ClassMetadata> classMeta = _sessionFactory.getAllClassMetadata();
for (ClassMetadata meta : classMeta.values()) {
addClass(meta);
}
return _rawMetadata;
}
void initMap() {
_rawMetadata = new RawMetadata();
_typeList = new ArrayList<HashMap<String, Object>>();
_typeNames = new HashSet<String>();
_resourceMap = new HashMap<String, Object>();
_fkMap = new HashMap<String, String>();
_rawMetadata.put("localQueryComparisonOptions", "caseInsensitiveSQL");
_rawMetadata.put("structuralTypes", _typeList);
_rawMetadata.put("resourceEntityTypeMap", _resourceMap);
_rawMetadata.foreignKeyMap = _fkMap;
}
/**
* Add the metadata for an entity.
*
* @param meta
*/
void addClass(ClassMetadata meta) {
Class type = meta.getMappedClass();
String classKey = getEntityTypeName(type);
HashMap<String, Object> cmap = new LinkedHashMap<String, Object>();
_typeList.add(cmap);
cmap.put("shortName", type.getSimpleName());
cmap.put("namespace", type.getPackage().getName());
EntityMetamodel metaModel = ((EntityPersister) meta).getEntityMetamodel();
String superTypeName = metaModel.getSuperclass();
if (superTypeName != null) {
ClassMetadata superMeta = _sessionFactory.getClassMetadata(superTypeName);
if (superMeta != null) {
Class superClass = superMeta.getMappedClass();
cmap.put("baseTypeName", getEntityTypeName(superClass));
}
}
String genType = "None";
if (meta instanceof EntityPersister) {
EntityPersister entityPersister = (EntityPersister) meta;
// multipart keys can never have an AutoGeneratedKeyType
if (entityPersister.hasIdentifierProperty()) {
IdentifierGenerator generator = entityPersister != null
? entityPersister.getIdentifierGenerator()
: null;
if (generator != null) {
if (generator instanceof IdentityGenerator) {
genType = "Identity";
} else if (generator instanceof Assigned || generator instanceof ForeignGenerator) {
genType = "None";
} else {
genType = "KeyGenerator";
}
// TODO find the real generator
}
}
}
cmap.put("autoGeneratedKeyType", genType);
String resourceName = pluralize(type.getSimpleName()); // TODO find the real name
cmap.put("defaultResourceName", resourceName);
_resourceMap.put(resourceName, classKey);
ArrayList<HashMap<String, Object>> dataArrayList = new ArrayList<HashMap<String, Object>>();
cmap.put("dataProperties", dataArrayList);
ArrayList<HashMap<String, Object>> navArrayList = new ArrayList<HashMap<String, Object>>();
cmap.put("navigationProperties", navArrayList);
addClassProperties(meta, dataArrayList, navArrayList);
}
/**
* Add the properties for an entity.
*
* @param meta
* @param pClass
* @param dataArrayList - will be populated with the data properties of the entity
* @param navArrayList - will be populated with the navigation properties of the entity
*/
void addClassProperties(ClassMetadata meta, ArrayList<HashMap<String, Object>> dataArrayList,
ArrayList<HashMap<String, Object>> navArrayList) {
AbstractEntityPersister persister = (AbstractEntityPersister) meta;
Class type = meta.getMappedClass();
HashSet<String> inheritedProperties = getSuperProperties(persister);
String[] propNames = meta.getPropertyNames();
Type[] propTypes = meta.getPropertyTypes();
PersistentClass persistentClass = _configuration.getClassMapping(type.getName());
boolean[] propNull = meta.getPropertyNullability();
for (int i = 0; i < propNames.length; i++) {
String propName = propNames[i];
if (inheritedProperties.contains(propName))
continue; // skip property defined on superclass
Type propType = propTypes[i];
if (!propType.isAssociationType()) // skip association types until
// we handle all the data types,
// so the relatedDataPropertyMap
// will be populated.
{
ArrayList<Selectable> propColumns = getColumns(persistentClass.getProperty(propName));
if (propType.isComponentType()) {
// complex type
ComponentType compType = (ComponentType) propType;
String complexTypeName = addComponent(compType, propColumns);
HashMap<String, Object> compMap = new HashMap<String, Object>();
compMap.put("nameOnServer", propName);
compMap.put("complexTypeName", complexTypeName);
compMap.put("isNullable", propNull[i]);
dataArrayList.add(compMap);
} else {
// data property
boolean isKey = meta.hasNaturalIdentifier() && contains(meta.getNaturalIdentifierProperties(), i);
boolean isVersion = meta.isVersioned() && i == meta.getVersionProperty();
Column col = (Column) propColumns.get(0);
HashMap<String, Object> dmap = makeDataProperty(propName, propType, col, propNull[i], isKey, isVersion);
dataArrayList.add(dmap);
}
}
}
// Hibernate identifiers are excluded from the list of data properties,
// so we have to add them separately
if (meta.hasIdentifierProperty() && !inheritedProperties.contains(meta.getIdentifierPropertyName())) {
Property property = persistentClass.getProperty(meta.getIdentifierPropertyName());
ArrayList<Selectable> propColumns = getColumns(property);
Column col = (Column) propColumns.get(0);
HashMap<String, Object> dmap = makeDataProperty(meta.getIdentifierPropertyName(), meta.getIdentifierType(), col, false,
true, false);
dataArrayList.add(0, dmap);
} else if (meta.getIdentifierType() != null && meta.getIdentifierType().isComponentType()) {
// composite key is a ComponentType
ComponentType compType = (ComponentType) meta.getIdentifierType();
// check that the component belongs to this class, not a superclass
if (compType.getReturnedClass() == type || meta.getIdentifierPropertyName() == null
|| !inheritedProperties.contains(meta.getIdentifierPropertyName())) {
String[] compNames = compType.getPropertyNames();
for (int i = 0; i < compNames.length; i++) {
String compName = compNames[i];
Type propType = compType.getSubtypes()[i];
if (!propType.isAssociationType()) {
Column col = getColumn(persistentClass, compName);
HashMap<String, Object> dmap = makeDataProperty(compName, propType, col,
compType.getPropertyNullability()[i], true, false);
dataArrayList.add(0, dmap);
} else {
HashMap<String, Object> assProp = makeAssociationProperty(persister, (AssociationType) propType, compName,
dataArrayList, true);
navArrayList.add(assProp);
}
}
}
}
// We do the association properties after the data properties, so we can
// do the foreign key lookups
for (int i = 0; i < propNames.length; i++) {
String propName = propNames[i];
if (inheritedProperties.contains(propName))
continue; // skip property defined on superclass
Type propType = propTypes[i];
if (propType.isAssociationType()) {
// navigation property
HashMap<String, Object> assProp = makeAssociationProperty(persister, (AssociationType) propType, propName,
dataArrayList, false);
navArrayList.add(assProp);
}
}
}
/**
* Return names of all properties that are defined in the mapped ancestors of the given
* persister. Note that unmapped superclasses are deliberately ignored, because they shouldn't
* affect the metadata.
*
* @param persister
* @return set of property names. Empty if the persister doesn't have a superclass.
*/
HashSet<String> getSuperProperties(AbstractEntityPersister persister) {
HashSet<String> set = new HashSet<String>();
String superClassName = persister.getMappedSuperclass();
if (superClassName == null)
return set;
ClassMetadata superMeta = _sessionFactory.getClassMetadata(superClassName);
if (superMeta == null)
return set;
String[] superProps = superMeta.getPropertyNames();
set.addAll(Arrays.asList(superProps));
set.add(superMeta.getIdentifierPropertyName());
return set;
}
ArrayList<Selectable> getColumns(Property pClassProp) {
Iterator iter = pClassProp.getColumnIterator();
ArrayList<Selectable> list = new ArrayList<Selectable>();
while (iter.hasNext())
list.add((Selectable) iter.next());
return list;
}
Column getColumn(PersistentClass persistentClass, String propName) {
try {
Property property = persistentClass.getProperty(propName);
ArrayList<Selectable> propColumns = getColumns(property);
Column col = (Column) propColumns.get(0);
return col;
} catch (MappingException mex) {
return null;
}
}
boolean contains(int[] array, int x) {
for (int j = 0; j < array.length; j++) {
if (array[j] == x)
return true;
}
return false;
}
boolean contains(String[] array, String x) {
for (int j = 0; j < array.length; j++) {
if (array[j].equals(x))
return true;
}
return false;
}
/**
* Adds a complex type definition
*
* @param compType - The complex type
* @param propColumns - The columns which the complex type spans. These are used to get length
* and defaultValues.
* @return The class name and namespace of the component.
*/
String addComponent(ComponentType compType, List<Selectable> propColumns) {
Class type = compType.getReturnedClass();
// "Location:#com.breeze.model"
String classKey = getEntityTypeName(type);
if (_typeNames.contains(classKey)) {
// Only add a complex type definition once.
return classKey;
}
HashMap<String, Object> cmap = new LinkedHashMap<String, Object>();
_typeList.add(0, cmap);
_typeNames.add(classKey);
cmap.put("shortName", type.getSimpleName());
cmap.put("namespace", type.getPackage().getName());
cmap.put("isComplexType", true);
ArrayList<HashMap<String, Object>> dataArrayList = new ArrayList<HashMap<String, Object>>();
cmap.put("dataProperties", dataArrayList);
String[] propNames = compType.getPropertyNames();
Type[] propTypes = compType.getSubtypes();
boolean[] propNull = compType.getPropertyNullability();
int colIndex = 0;
for (int i = 0; i < propNames.length; i++) {
Type propType = propTypes[i];
String propName = propNames[i];
if (propType.isComponentType()) {
// nested complex type
ComponentType compType2 = (ComponentType) propType;
int span = compType2.getColumnSpan((Mapping) _sessionFactory);
List<Selectable> subColumns = propColumns.subList(colIndex, colIndex + span);
String complexTypeName = addComponent(compType2, subColumns);
HashMap<String, Object> compMap = new HashMap<String, Object>();
compMap.put("nameOnServer", propName);
compMap.put("complexTypeName", complexTypeName);
compMap.put("isNullable", propNull[i]);
dataArrayList.add(compMap);
colIndex += span;
} else {
// data property
Column col = (Column) propColumns.get(colIndex);
HashMap<String, Object> dmap = makeDataProperty(propName, propType, col, propNull[i], false, false);
dataArrayList.add(dmap);
colIndex++;
}
}
return classKey;
}
/**
* Make data property metadata for the entity
*
* @param propName - name of the property on the server
* @param type - data type of the property, e.g. Int32
* @param col - the Column for this property; used for length and default value
* @param isNullable - whether the property is nullable in the database
* @param isKey - true if this property is part of the key for the entity
* @param isVersion - true if this property contains the version of the entity (for a
* concurrency strategy)
* @return data property definition
*/
private HashMap<String, Object> makeDataProperty(String propName, Type type, Column col, boolean isNullable, boolean isKey,
boolean isVersion) {
String newType = BreezeTypeMap.get(type.getName().toLowerCase());
String typeName = newType != null ? newType : type.getName();
HashMap<String, Object> dmap = new LinkedHashMap<String, Object>();
dmap.put("nameOnServer", propName);
if (typeName == "org.hibernate.type.EnumType") {
typeName = "String";
dmap.put("enumType", type.getReturnedClass().getName());
}
dmap.put("dataType", typeName);
dmap.put("isNullable", isNullable);
if (col != null && col.getDefaultValue() != null) {
dmap.put("defaultValue", col.getDefaultValue());
}
if (isKey) {
dmap.put("isPartOfKey", true);
}
if (isVersion) {
dmap.put("concurrencyMode", "Fixed");
}
ArrayList<HashMap<String, String>> validators = new ArrayList<HashMap<String, String>>();
if (!isNullable) {
validators.add(newMap("name", "required"));
}
if ((!NoLength.contains(typeName)) && col != null && col.getLength() > 0) {
dmap.put("maxLength", col.getLength());
validators.add(newMap("maxLength", Integer.toString(col.getLength()), "name", "maxLength"));
}
String validationType = ValidationTypeMap.get(typeName);
if (validationType != null) {
validators.add(newMap("name", validationType));
}
if (!validators.isEmpty())
dmap.put("validators", validators);
return dmap;
}
/**
* Make a HashMap populated with the given key and value.
*
* @param key
* @param value
* @return
*/
static HashMap<String, String> newMap(String key, String value) {
HashMap<String, String> map = new HashMap<String, String>();
map.put(key, value);
return map;
}
static HashMap<String, String> newMap(String key, String value, String key2, String value2) {
HashMap<String, String> map = newMap(key, value);
map.put(key2, value2);
return map;
}
/**
* Make association property metadata for the entity. Also populates the _fkMap which is used
* for related-entity fixup when saving.
*
* @param containingType
* @param propType
* @param propName
* @param columnNames
* @param pClass
* @param relatedDataPropertyMap
* @param isKey
* @return association property definition
*/
private HashMap<String, Object> makeAssociationProperty(AbstractEntityPersister containingPersister, AssociationType propType,
String propName,
ArrayList<HashMap<String, Object>> dataProperties, boolean isKey) {
HashMap<String, Object> nmap = new LinkedHashMap<String, Object>();
nmap.put("nameOnServer", propName);
Class relatedEntityType = getEntityType(propType);
nmap.put("entityTypeName", getEntityTypeName(relatedEntityType));
nmap.put("isScalar", !propType.isCollectionType());
// the associationName must be the same at both ends of the association.
Class containingType = containingPersister.getMappedClass();
String[] columnNames = getPropertyColumnNames(containingPersister, propName, propType);
nmap.put("associationName",
getAssociationName(containingType.getSimpleName(), relatedEntityType.getSimpleName(), columnNames));
String[] fkNames = null;
if (propType.isCollectionType()) {
// inverse foreign key
Joinable joinable = propType.getAssociatedJoinable((SessionFactoryImplementor) this._sessionFactory);
if (joinable instanceof AbstractCollectionPersister) {
// many-to-many relationships do not have a direct connection on
// the client or in metadata
AbstractEntityPersister elementPersister = (AbstractEntityPersister) ((AbstractCollectionPersister) joinable)
.getElementPersister();
if (elementPersister != null) {
fkNames = getPropertyNamesForColumns(elementPersister, columnNames);
if (fkNames != null) {
nmap.put("invForeignKeyNamesOnServer", fkNames);
}
}
}
} else {
// Not a collection type - a many-to-one or one-to-one association
String entityRelationship = containingType.getName() + '.' + propName;
// Look up the related foreign key name using the column name
fkNames = getPropertyNamesForColumns(containingPersister, columnNames);
if (fkNames != null)
{
if (propType.getForeignKeyDirection() == ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT) {
nmap.put("foreignKeyNamesOnServer", fkNames);
} else {
nmap.put("invForeignKeyNamesOnServer", fkNames);
}
// For many-to-one and one-to-one associations, save the relationship in _fkMap
// for re-establishing relationships during save
_fkMap.put(entityRelationship, catColumnNames(fkNames, ','));
if (isKey) {
for (String fkName : fkNames) {
HashMap<String, Object> relatedDataProperty = findPropertyByName(dataProperties, fkName);
if (!relatedDataProperty.containsKey("isPartOfKey")) {
relatedDataProperty.put("isPartOfKey", true);
}
}
}
}
else if (fkNames == null) {
nmap.put("foreignKeyNamesOnServer", columnNames);
nmap.put("ERROR", "Could not find matching fk for property " + entityRelationship);
_fkMap.put(entityRelationship, catColumnNames(columnNames, ','));
throw new IllegalArgumentException("Could not find matching fk for property " + entityRelationship);
}
}
return nmap;
}
/**
* Get the type name in the form "Order:#northwind.model"
*
* @param clazz
* @return
*/
String getEntityTypeName(Class clazz) {
// return clazz.getName();
return clazz.getSimpleName() + ":#" + clazz.getPackage().getName();
}
/**
* Get the column names for a given property as an array of unbracketed,
* lowercase names. For a collection property, the column name is the inverse foreign key (i.e.
* the column on the other table that points back to the persister's table)
*/
String[] getPropertyColumnNames(AbstractEntityPersister persister, String propertyName, Type propType) {
String[] propColumnNames = null;
if (propType.isCollectionType()) {
propColumnNames = ((CollectionType) propType).getAssociatedJoinable((SessionFactoryImplementor) this._sessionFactory)
.getKeyColumnNames();
} else {
propColumnNames = persister.getPropertyColumnNames(propertyName);
}
if (propColumnNames == null || propColumnNames.length == 0) {
// this happens when the property is part of the key
propColumnNames = persister.getKeyColumnNames();
}
// HACK for formula: when using formula propColumnNames[0] equals null
if (propColumnNames[0] == null)
{
propColumnNames = new String[] { propertyName };
}
return unBracket(propColumnNames);
}
/**
* Gets the properties matching the given columns. May be a component, but will not be an association.
* @param persister
* @param columnNames
* @return
*/
static String[] getPropertyNamesForColumns(AbstractEntityPersister persister, String[] columnNames) {
String[] propNames = persister.getPropertyNames();
Type[] propTypes = persister.getPropertyTypes();
for (int i = 0; i < propNames.length; i++) {
String propName = propNames[i];
Type propType = propTypes[i];
if (propType.isAssociationType()) continue;
String[] columnArray = persister.getPropertyColumnNames(i);
if (namesEqual(columnArray, columnNames)) return new String[] { propName };
}
// If we got here, maybe the property is the identifier
String[] keyColumnArray = persister.getKeyColumnNames();
if (namesEqual(keyColumnArray, columnNames))
{
if (persister.getIdentifierPropertyName() != null)
{
return new String[] { persister.getIdentifierPropertyName() };
}
if (persister.getIdentifierType().isComponentType())
{
ComponentType compType = (ComponentType) persister.getIdentifierType();
return compType.getPropertyNames();
}
}
if (columnNames.length > 1)
{
// go one-by-one through columnNames, trying to find a matching property.
// TODO: maybe this should split columnNames into all possible combinations of ordered subsets, and try those
ArrayList<String> propList = new ArrayList<String>();
String[] prop = new String[1];
for (int i = 0; i < columnNames.length; i++)
{
prop[0] = columnNames[i];
String[] names = getPropertyNamesForColumns(persister, prop); // recursive call
if (names != null) propList.addAll(Arrays.asList(names));
}
if (propList.size() > 0) return (String[]) propList.toArray();
}
return null;
}
/**
* Unbrackets the column names and concatenates them into a comma-delimited string
*/
static String catColumnNames(String[] columnNames, char delim) {
StringBuilder sb = new StringBuilder();
for (String s : columnNames) {
if (sb.length() > 0)
sb.append(delim);
sb.append(unBracket(s));
}
return sb.toString(); //.toLowerCase();
}
/**
* Return true if the two arrays contain the same names, false otherwise.
* Names are compared after unBracket(), and are case-insensitive.
* @param a
* @param b
* @return
*/
static boolean namesEqual(String[] a, String[] b)
{
if (a.length != b.length) return false;
for (int i = 0; i < a.length; i++)
{
if (!unBracket(a[i]).equalsIgnoreCase(unBracket(b[i]))) return false;
}
return true;
}
/**
* Get the column name without square brackets or quotes around it. E.g. "[OrderID]" -> OrderID
* Because sometimes Hibernate gives us brackets, and sometimes it doesn't. Double-quotes happen
* with SQL CE. Backticks happen with MySQL.
*/
static String unBracket(String name) {
name = (name.charAt(0) == '[') ? name.substring(1, name.length() - 1) : name;
name = (name.charAt(0) == '"') ? name.substring(1, name.length() - 1) : name;
name = (name.charAt(0) == '`') ? name.substring(1, name.length() - 1) : name;
return name;
}
/**
* @return a new array containing the unbracketed names
*/
static String[] unBracket(String[] names) {
String[] u = new String[names.length];
for (int i = 0; i < names.length; i++)
{
u[i] = unBracket(names[i]);
}
return u;
}
/**
* Find the property in the list that has the given name.
* @param properties list of DataProperty or NavigationProperty maps
* @param name matched against the nameOnServer value of entries in the list
* @return the found property map, or null if not found.
*/
static HashMap<String, Object> findPropertyByName(ArrayList<HashMap<String, Object>> properties, String name)
{
Object nameOnServer;
for (HashMap<String, Object> prop : properties)
{
nameOnServer = prop.get("nameOnServer");
if (nameOnServer != null) {
if (((String) nameOnServer).equalsIgnoreCase(name)) return prop;
}
}
return null;
}
/**
* Get the Breeze name of the entity type. For collections, Breeze expects the name of the
* element type.
*
* @param propType
* @return
*/
Class getEntityType(AssociationType propType) {
if (!propType.isCollectionType())
return propType.getReturnedClass();
CollectionType collType = (CollectionType) propType;
Type elementType = collType.getElementType((SessionFactoryImplementor) _sessionFactory);
return elementType.getReturnedClass();
}
/**
* Lame pluralizer. Assumes we just need to add a suffix.
*/
static String pluralize(String s) {
if (s == null || s.isEmpty())
return s;
int last = s.length() - 1;
char c = s.charAt(last);
switch (c) {
case 'y':
return s.substring(0, last) + "ies";
default:
return s + 's';
}
}
/**
* Creates an association name from two entity names. For consistency, puts the entity names in
* alphabetical order.
*
* @param name1
* @param name2
* @param columnNames - name of the column(s) on the child entity
* @return
*/
static String getAssociationName(String name1, String name2, String[] columnNames) {
String cols = catColumnNames(columnNames, '_');
if (name1.compareTo(name2) < 0) return ASSN + name1 + '_' + name2 + '_' + cols;
else return ASSN + name2 + '_' + name1 + '_' + cols;
}
static final String ASSN = "AN_";
// Map of Hibernate datatype to Breeze datatype.
static HashMap<String, String> BreezeTypeMap;
// Map of data type to Breeze validation type
static HashMap<String, String> ValidationTypeMap;
// Set of Breeze types which don't need a maxlength validation
static HashSet<String> NoLength;
static {
BreezeTypeMap = new HashMap<String, String>();
BreezeTypeMap.put("byte[]", "Binary");
BreezeTypeMap.put("binary", "Binary");
BreezeTypeMap.put("binaryblob", "Binary");
BreezeTypeMap.put("blob", "Binary");
BreezeTypeMap.put("timestamp", "DateTime");
BreezeTypeMap.put("timeastimespan", "Time");
BreezeTypeMap.put("short", "Int16");
BreezeTypeMap.put("integer", "Int32");
BreezeTypeMap.put("long", "Int64");
BreezeTypeMap.put("boolean", "Boolean");
BreezeTypeMap.put("byte", "Byte");
BreezeTypeMap.put("datetime", "DateTime");
BreezeTypeMap.put("date", "DateTime");
BreezeTypeMap.put("datetimeoffset", "DateTimeOffset");
BreezeTypeMap.put("big_decimal", "Decimal");
BreezeTypeMap.put("double", "Double");
BreezeTypeMap.put("float", "Single");
BreezeTypeMap.put("uuid", "Guid");
BreezeTypeMap.put("uuid-char", "Guid");
BreezeTypeMap.put("uuid-binary", "Guid");
BreezeTypeMap.put("string", "String");
BreezeTypeMap.put("time", "Time");
NoLength = new HashSet<String>();
NoLength.add("Byte");
NoLength.add("Binary");
NoLength.add("Int16");
NoLength.add("Int32");
NoLength.add("Int64");
NoLength.add("DateTime");
NoLength.add("DateTimeOffset");
NoLength.add("Time");
NoLength.add("Boolean");
NoLength.add("Guid");
NoLength.add("Double");
NoLength.add("Single");
NoLength.add("Decimal");
ValidationTypeMap = new HashMap<String, String>();
ValidationTypeMap.put("Boolean", "bool");
ValidationTypeMap.put("Byte", "byte");
ValidationTypeMap.put("DateTime", "date");
ValidationTypeMap.put("DateTimeOffset", "date");
ValidationTypeMap.put("Decimal", "number");
ValidationTypeMap.put("Double", "number");
ValidationTypeMap.put("Single", "number");
ValidationTypeMap.put("Guid", "guid");
ValidationTypeMap.put("Int16", "int16");
ValidationTypeMap.put("Int32", "int32");
ValidationTypeMap.put("Int64", "int64");
ValidationTypeMap.put("Float", "number");
// ValidationTypeMap.put("String", "string");
ValidationTypeMap.put("Time", "duration");
}
/**
* Extract the Configuration from the ServiceRegistry exposed by SessionFactoryImpl. Works in
* Hibernate 4.3, but will probably break in a future version as they keep trying to make the
* configuration harder to access (for some reason). Hopefully they will provide a interface to
* get the full mapping data again.
*
* @param sessionFactory
*/
Configuration getConfigurationFromRegistry(SessionFactory sessionFactory) {
ServiceRegistryImplementor serviceRegistry = ((SessionFactoryImplementor) _sessionFactory).getServiceRegistry();
SessionFactoryServiceRegistryImpl impl = (SessionFactoryServiceRegistryImpl) serviceRegistry;
Configuration cfg = null;
try {
Field configurationField = SessionFactoryServiceRegistryImpl.class.getDeclaredField("configuration");
configurationField.setAccessible(true);
Object configurationObject = configurationField.get(impl);
cfg = (Configuration) configurationObject;
} catch (Exception e) {
e.printStackTrace();
}
if (cfg == null) {
throw new RuntimeException(
"Unable to get the Configuration from the service registry. Please provide the Configuration in the constructor.");
}
return cfg;
}
}