diff --git a/hibernate4/src/main/java/com/fasterxml/jackson/datatype/hibernate4/Hibernate4Module.java b/hibernate4/src/main/java/com/fasterxml/jackson/datatype/hibernate4/Hibernate4Module.java index 396a319c..7225c007 100644 --- a/hibernate4/src/main/java/com/fasterxml/jackson/datatype/hibernate4/Hibernate4Module.java +++ b/hibernate4/src/main/java/com/fasterxml/jackson/datatype/hibernate4/Hibernate4Module.java @@ -28,21 +28,21 @@ public enum Feature { * Default value is true. */ USE_TRANSIENT_ANNOTATION(true), - + /** * If FORCE_LAZY_LOADING is false, this feature serializes uninitialized lazy loading proxies as - * {"identifierName":"identifierValue"} rather than null. + * {"identifierName":"identifierValue"} rather than null. *

* Default value is false. *

- * Note that the name of the identifier property can only be determined if + * Note that the name of the identifier property can only be determined if *

- * Otherwise, the entity name will be used instead. + * Otherwise, the entity name will be used instead. */ SERIALIZE_IDENTIFIER_FOR_LAZY_NOT_LOADED_OBJECTS(false), @@ -58,7 +58,7 @@ public enum Feature { *

* Default value is false, meaning that laziness is considered to be the * default value. - * + * * @since 2.4 */ REQUIRE_EXPLICIT_LAZY_LOADING_MARKER(false), @@ -78,7 +78,7 @@ public enum Feature { * @since 2.8.2 */ REPLACE_PERSISTENT_COLLECTIONS(false), - + /** * Using {@link #FORCE_LAZY_LOADING} may result in * `javax.persistence.EntityNotFoundException`. This flag configures Jackson to @@ -86,8 +86,16 @@ public enum Feature { * * @since 2.10 */ - WRITE_MISSING_ENTITIES_AS_NULL(false) - ; + WRITE_MISSING_ENTITIES_AS_NULL(false), + + /** + * Feature that may be disables to unwrap the identifier + * of the serialized entity, returning a value instead of + * an object. + * + * @since 2.12 + */ + WRAP_IDENTIFIER_IN_OBJECT(true); final boolean _defaultState; final int _mask; @@ -106,7 +114,7 @@ public static int collectDefaults() } return flags; } - + private Feature(boolean defaultState) { _defaultState = defaultState; _mask = (1 << ordinal()); @@ -118,7 +126,7 @@ private Feature(boolean defaultState) { } protected final static int DEFAULT_FEATURES = Feature.collectDefaults(); - + /** * Bit flag composed of bits that indicate which * {@link Feature}s diff --git a/hibernate4/src/main/java/com/fasterxml/jackson/datatype/hibernate4/HibernateProxySerializer.java b/hibernate4/src/main/java/com/fasterxml/jackson/datatype/hibernate4/HibernateProxySerializer.java index f570a8bf..3d46ee06 100644 --- a/hibernate4/src/main/java/com/fasterxml/jackson/datatype/hibernate4/HibernateProxySerializer.java +++ b/hibernate4/src/main/java/com/fasterxml/jackson/datatype/hibernate4/HibernateProxySerializer.java @@ -46,6 +46,7 @@ public class HibernateProxySerializer protected final boolean _forceLazyLoading; protected final boolean _serializeIdentifier; protected final boolean _nullMissingEntities; + protected final boolean _wrappedIdentifier; protected final Mapping _mapping; /** @@ -62,26 +63,31 @@ public class HibernateProxySerializer public HibernateProxySerializer(boolean forceLazyLoading) { - this(forceLazyLoading, false, false, null, null); + this(forceLazyLoading, false, false, true, null, null); } public HibernateProxySerializer(boolean forceLazyLoading, boolean serializeIdentifier) { - this(forceLazyLoading, serializeIdentifier, false, null, null); + this(forceLazyLoading, serializeIdentifier, false, true, null, null); } public HibernateProxySerializer(boolean forceLazyLoading, boolean serializeIdentifier, Mapping mapping) { - this(forceLazyLoading, serializeIdentifier, false, mapping, null); + this(forceLazyLoading, serializeIdentifier, false, true, mapping, null); } public HibernateProxySerializer(boolean forceLazyLoading, boolean serializeIdentifier, boolean nullMissingEntities, Mapping mapping) { - this(forceLazyLoading, serializeIdentifier, nullMissingEntities, mapping, null); + this(forceLazyLoading, serializeIdentifier, nullMissingEntities, true, mapping, null); } - public HibernateProxySerializer(boolean forceLazyLoading, boolean serializeIdentifier, boolean nullMissingEntities, Mapping mapping, - BeanProperty property) { + public HibernateProxySerializer(boolean forceLazyLoading, boolean serializeIdentifier, boolean nullMissingEntities, boolean wrappedIdentifier, Mapping mapping) { + this(forceLazyLoading, serializeIdentifier, nullMissingEntities, wrappedIdentifier, mapping, null); + } + + public HibernateProxySerializer(boolean forceLazyLoading, boolean serializeIdentifier, boolean nullMissingEntities, boolean wrappedIdentifier, Mapping mapping, + BeanProperty property) { _forceLazyLoading = forceLazyLoading; _serializeIdentifier = serializeIdentifier; _nullMissingEntities = nullMissingEntities; + _wrappedIdentifier = wrappedIdentifier; _mapping = mapping; _dynamicSerializers = PropertySerializerMap.emptyForProperties(); _property = property; @@ -90,8 +96,8 @@ public HibernateProxySerializer(boolean forceLazyLoading, boolean serializeIdent @Override public JsonSerializer createContextual(SerializerProvider prov, BeanProperty property) { return new HibernateProxySerializer(this._forceLazyLoading, _serializeIdentifier, _nullMissingEntities, - _mapping, property); - } + _wrappedIdentifier, _mapping, property); + } /* /********************************************************************** @@ -103,7 +109,7 @@ public JsonSerializer createContextual(SerializerProvider prov, BeanProperty public boolean isEmpty(SerializerProvider provider, HibernateProxy value) { return (value == null) || (findProxied(value) == null); } - + @Override public void serialize(HibernateProxy value, JsonGenerator jgen, SerializerProvider provider) throws IOException @@ -181,29 +187,21 @@ protected JsonSerializer findSerializer(SerializerProvider provider, Obj * Helper method for finding value being proxied, if it is available * or if it is to be forced to be loaded. */ - protected Object findProxied(HibernateProxy proxy) + protected Object findProxied(final HibernateProxy proxy) { LazyInitializer init = proxy.getHibernateLazyInitializer(); if (!_forceLazyLoading && init.isUninitialized()) { if (_serializeIdentifier) { - String idName; - if (_mapping != null) { - idName = _mapping.getIdentifierPropertyName(init.getEntityName()); + final Object idValue = init.getIdentifier(); + final Object result; + if (_wrappedIdentifier) { + final HashMap map = new HashMap<>(); + map.put(getIdentifierPropertyName(init), idValue); + result = map; } else { - final SessionImplementor session = init.getSession(); - if (session != null) { - idName = session.getFactory().getIdentifierPropertyName(init.getEntityName()); - } else { - idName = ProxyReader.getIdentifierPropertyName(init); - if (idName == null) { - idName = init.getEntityName(); - } - } + result = idValue; } - final Object idValue = init.getIdentifier(); - HashMap map = new HashMap(); - map.put(idName, idValue); - return map; + return result; } return null; } @@ -217,12 +215,36 @@ protected Object findProxied(HibernateProxy proxy) } } } - + + /** + * Helper method to retrieve the name of the identifier property of the + * specified lazy initializer. + * @param init Lazy initializer to obtain identifier property name from. + * @return Name of the identity property of the specified lazy initializer. + */ + private String getIdentifierPropertyName(final LazyInitializer init) { + String idName; + if (_mapping != null) { + idName = _mapping.getIdentifierPropertyName(init.getEntityName()); + } else { + final SessionImplementor session = init.getSession(); + if (session != null) { + idName = session.getFactory().getIdentifierPropertyName(init.getEntityName()); + } else { + idName = ProxyReader.getIdentifierPropertyName(init); + if (idName == null) { + idName = init.getEntityName(); + } + } + } + return idName; + } + /** * Inspects a Hibernate proxy to try and determine the name of the identifier property - * (Hibernate proxies know the getter of the identifier property because it receives special - * treatment in the invocation handler). Alas, the field storing the method reference is - * private and has no getter, so we must resort to ugly reflection hacks to read its value ... + * (Hibernate proxies know the getter of the identifier property because it receives special + * treatment in the invocation handler). Alas, the field storing the method reference is + * private and has no getter, so we must resort to ugly reflection hacks to read its value ... */ protected static class ProxyReader { @@ -235,7 +257,7 @@ protected static class ProxyReader { getIdentifierMethodField.setAccessible(true); } catch (Exception e) { // should never happen: the field exists in all versions of hibernate 4 and 5 - throw new RuntimeException(e); + throw new RuntimeException(e); } } diff --git a/hibernate4/src/main/java/com/fasterxml/jackson/datatype/hibernate4/HibernateSerializers.java b/hibernate4/src/main/java/com/fasterxml/jackson/datatype/hibernate4/HibernateSerializers.java index 1e4faaad..a2cb569b 100644 --- a/hibernate4/src/main/java/com/fasterxml/jackson/datatype/hibernate4/HibernateSerializers.java +++ b/hibernate4/src/main/java/com/fasterxml/jackson/datatype/hibernate4/HibernateSerializers.java @@ -14,6 +14,7 @@ public class HibernateSerializers extends Serializers.Base protected final boolean _forceLoading; protected final boolean _serializeIdentifiers; protected final boolean _nullMissingEntities; + protected final boolean _wrappedIdentifier; protected final Mapping _mapping; public HibernateSerializers(int features) { @@ -25,6 +26,7 @@ public HibernateSerializers(Mapping mapping, int features) _forceLoading = Feature.FORCE_LAZY_LOADING.enabledIn(features); _serializeIdentifiers = Feature.SERIALIZE_IDENTIFIER_FOR_LAZY_NOT_LOADED_OBJECTS.enabledIn(features); _nullMissingEntities = Feature.WRITE_MISSING_ENTITIES_AS_NULL.enabledIn(features); + _wrappedIdentifier = Feature.WRAP_IDENTIFIER_IN_OBJECT.enabledIn(features); _mapping = mapping; } @@ -34,7 +36,7 @@ public JsonSerializer findSerializer(SerializationConfig config, { Class raw = type.getRawClass(); if (HibernateProxy.class.isAssignableFrom(raw)) { - return new HibernateProxySerializer(_forceLoading, _serializeIdentifiers, _nullMissingEntities, _mapping); + return new HibernateProxySerializer(_forceLoading, _serializeIdentifiers, _nullMissingEntities, _wrappedIdentifier, _mapping); } return null; } diff --git a/hibernate5/src/main/java/com/fasterxml/jackson/datatype/hibernate5/Hibernate5Module.java b/hibernate5/src/main/java/com/fasterxml/jackson/datatype/hibernate5/Hibernate5Module.java index 392b4f37..538990ce 100644 --- a/hibernate5/src/main/java/com/fasterxml/jackson/datatype/hibernate5/Hibernate5Module.java +++ b/hibernate5/src/main/java/com/fasterxml/jackson/datatype/hibernate5/Hibernate5Module.java @@ -86,7 +86,16 @@ public enum Feature { * * @since 2.10 */ - WRITE_MISSING_ENTITIES_AS_NULL(false) + WRITE_MISSING_ENTITIES_AS_NULL(false), + + /** + * Feature that may be disables to unwrap the identifier + * of the serialized entity, returning a value instead of + * an object. + * + * @since 2.12 + */ + WRAP_IDENTIFIER_IN_OBJECT(true) ; final boolean _defaultState; diff --git a/hibernate5/src/main/java/com/fasterxml/jackson/datatype/hibernate5/HibernateProxySerializer.java b/hibernate5/src/main/java/com/fasterxml/jackson/datatype/hibernate5/HibernateProxySerializer.java index 6245ad84..cb1fc6f7 100644 --- a/hibernate5/src/main/java/com/fasterxml/jackson/datatype/hibernate5/HibernateProxySerializer.java +++ b/hibernate5/src/main/java/com/fasterxml/jackson/datatype/hibernate5/HibernateProxySerializer.java @@ -47,6 +47,7 @@ public class HibernateProxySerializer protected final boolean _forceLazyLoading; protected final boolean _serializeIdentifier; protected final boolean _nullMissingEntities; + protected final boolean _wrappedIdentifier; protected final Mapping _mapping; /** @@ -63,26 +64,36 @@ public class HibernateProxySerializer public HibernateProxySerializer(boolean forceLazyLoading) { - this(forceLazyLoading, false, false, null, null); + this(forceLazyLoading, false, false, true, null, null); } public HibernateProxySerializer(boolean forceLazyLoading, boolean serializeIdentifier) { - this(forceLazyLoading, serializeIdentifier, false, null, null); + this(forceLazyLoading, serializeIdentifier, false, true, null, null); } public HibernateProxySerializer(boolean forceLazyLoading, boolean serializeIdentifier, Mapping mapping) { - this(forceLazyLoading, serializeIdentifier, false, mapping, null); + this(forceLazyLoading, serializeIdentifier, false, true, mapping, null); } public HibernateProxySerializer(boolean forceLazyLoading, boolean serializeIdentifier, boolean nullMissingEntities, Mapping mapping) { - this(forceLazyLoading, serializeIdentifier, nullMissingEntities, mapping, null); + this(forceLazyLoading, serializeIdentifier, nullMissingEntities, true, mapping, null); + } + + public HibernateProxySerializer(boolean forceLazyLoading, boolean serializeIdentifier, boolean nullMissingEntities, boolean wrappedIdentifier, Mapping mapping) { + this(forceLazyLoading, serializeIdentifier, nullMissingEntities, wrappedIdentifier, mapping, null); } public HibernateProxySerializer(boolean forceLazyLoading, boolean serializeIdentifier, boolean nullMissingEntities, Mapping mapping, BeanProperty property) { + this(forceLazyLoading, serializeIdentifier, nullMissingEntities, true, mapping, property); + } + + public HibernateProxySerializer(boolean forceLazyLoading, boolean serializeIdentifier, boolean nullMissingEntities, boolean wrappedIdentifier, Mapping mapping, + BeanProperty property) { _forceLazyLoading = forceLazyLoading; _serializeIdentifier = serializeIdentifier; _nullMissingEntities = nullMissingEntities; + _wrappedIdentifier = wrappedIdentifier; _mapping = mapping; _dynamicSerializers = PropertySerializerMap.emptyForProperties(); _property = property; @@ -187,22 +198,14 @@ protected Object findProxied(HibernateProxy proxy) LazyInitializer init = proxy.getHibernateLazyInitializer(); if (!_forceLazyLoading && init.isUninitialized()) { if (_serializeIdentifier) { - String idName; - if (_mapping != null) { - idName = _mapping.getIdentifierPropertyName(init.getEntityName()); + final Object idValue = init.getIdentifier(); + if (_wrappedIdentifier) { + HashMap map = new HashMap<>(); + map.put(getIdentifierPropertyName(init), idValue); + return map; } else { - idName = ProxySessionReader.getIdentifierPropertyName(init); - if (idName == null) { - idName = ProxyReader.getIdentifierPropertyName(init); - if (idName == null) { - idName = init.getEntityName(); - } - } + return idValue; } - final Object idValue = init.getIdentifier(); - HashMap map = new HashMap(); - map.put(idName, idValue); - return map; } return null; } @@ -216,6 +219,28 @@ protected Object findProxied(HibernateProxy proxy) } } } + + /** + * Helper method to retrieve the name of the identifier property of the + * specified lazy initializer. + * @param init Lazy initializer to obtain identifier property name from. + * @return Name of the identity property of the specified lazy initializer. + */ + private String getIdentifierPropertyName(final LazyInitializer init) { + String idName; + if (_mapping != null) { + idName = _mapping.getIdentifierPropertyName(init.getEntityName()); + } else { + idName = ProxySessionReader.getIdentifierPropertyName(init); + if (idName == null) { + idName = ProxyReader.getIdentifierPropertyName(init); + if (idName == null) { + idName = init.getEntityName(); + } + } + } + return idName; + } /** * Inspects a Hibernate proxy to try and determine the name of the identifier property diff --git a/hibernate5/src/main/java/com/fasterxml/jackson/datatype/hibernate5/HibernateSerializers.java b/hibernate5/src/main/java/com/fasterxml/jackson/datatype/hibernate5/HibernateSerializers.java index a89440a0..2669e55f 100644 --- a/hibernate5/src/main/java/com/fasterxml/jackson/datatype/hibernate5/HibernateSerializers.java +++ b/hibernate5/src/main/java/com/fasterxml/jackson/datatype/hibernate5/HibernateSerializers.java @@ -13,6 +13,7 @@ public class HibernateSerializers extends Serializers.Base protected final boolean _forceLoading; protected final boolean _serializeIdentifiers; protected final boolean _nullMissingEntities; + protected final boolean _wrappedIdentifier; protected final Mapping _mapping; public HibernateSerializers(int features) { @@ -24,6 +25,7 @@ public HibernateSerializers(Mapping mapping, int features) _forceLoading = Hibernate5Module.Feature.FORCE_LAZY_LOADING.enabledIn(features); _serializeIdentifiers = Hibernate5Module.Feature.SERIALIZE_IDENTIFIER_FOR_LAZY_NOT_LOADED_OBJECTS.enabledIn(features); _nullMissingEntities = Hibernate5Module.Feature.WRITE_MISSING_ENTITIES_AS_NULL.enabledIn(features); + _wrappedIdentifier = Hibernate5Module.Feature.WRAP_IDENTIFIER_IN_OBJECT.enabledIn(features); _mapping = mapping; } @@ -33,7 +35,7 @@ public JsonSerializer findSerializer(SerializationConfig config, { Class raw = type.getRawClass(); if (HibernateProxy.class.isAssignableFrom(raw)) { - return new HibernateProxySerializer(_forceLoading, _serializeIdentifiers, _nullMissingEntities, _mapping); + return new HibernateProxySerializer(_forceLoading, _serializeIdentifiers, _nullMissingEntities, _wrappedIdentifier, _mapping); } return null; }