Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package org.hibernate.boot.internal;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collections;
Expand Down Expand Up @@ -80,6 +81,7 @@
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
import org.hibernate.stat.Statistics;
import org.hibernate.type.format.FormatMapper;
import org.hibernate.type.format.FormatMapperCreationContext;
import org.hibernate.type.format.jaxb.JaxbXmlFormatMapper;

import jakarta.persistence.criteria.Nulls;
Expand Down Expand Up @@ -294,18 +296,26 @@ public SessionFactoryOptionsBuilder(StandardServiceRegistry serviceRegistry, Boo
settings.get( JAKARTA_VALIDATION_FACTORY )
);

final var formatMapperCreationContext = new FormatMapperCreationContext() {
@Override
public BootstrapContext getBootstrapContext() {
return context;
}
};
jsonFormatMapper = jsonFormatMapper(
settings.get( JSON_FORMAT_MAPPER ),
!getBoolean( ORACLE_OSON_DISABLED, settings),
strategySelector
strategySelector,
formatMapperCreationContext
);

xmlFormatMapper = xmlFormatMapper(
settings.get( XML_FORMAT_MAPPER ),
strategySelector,
xmlFormatMapperLegacyFormatEnabled =
context.getMetadataBuildingOptions()
.isXmlFormatMapperLegacyFormatEnabled()
.isXmlFormatMapperLegacyFormatEnabled(),
formatMapperCreationContext
);

sessionFactoryName = (String) settings.get( SESSION_FACTORY_NAME );
Expand Down Expand Up @@ -852,39 +862,64 @@ private PhysicalConnectionHandlingMode interpretConnectionHandlingMode(
.getDefaultConnectionHandlingMode();
}

private static FormatMapper jsonFormatMapper(Object setting, boolean osonExtensionEnabled, StrategySelector selector) {
private static FormatMapper jsonFormatMapper(Object setting, boolean osonExtensionEnabled, StrategySelector selector, FormatMapperCreationContext creationContext) {
return formatMapper(
setting,
selector,
() -> {
// Prefer the OSON Jackson FormatMapper by default if available
final FormatMapper jsonJacksonFormatMapper =
osonExtensionEnabled && isJacksonOsonExtensionAvailable()
? getOsonJacksonFormatMapperOrNull()
: getJsonJacksonFormatMapperOrNull();
? getOsonJacksonFormatMapperOrNull( creationContext )
: getJsonJacksonFormatMapperOrNull( creationContext );
return jsonJacksonFormatMapper != null
? jsonJacksonFormatMapper
: getJakartaJsonBFormatMapperOrNull();
}
},
creationContext
);
}

private static FormatMapper xmlFormatMapper(Object setting, StrategySelector selector, boolean legacyFormat) {
private static FormatMapper xmlFormatMapper(Object setting, StrategySelector selector, boolean legacyFormat, FormatMapperCreationContext creationContext) {
return formatMapper(
setting,
selector,
() -> {
final FormatMapper jacksonFormatMapper =
getXMLJacksonFormatMapperOrNull( legacyFormat );
final FormatMapper jacksonFormatMapper = getXMLJacksonFormatMapperOrNull( creationContext );
return jacksonFormatMapper != null
? jacksonFormatMapper
: new JaxbXmlFormatMapper( legacyFormat );
}
},
creationContext
);
}

private static FormatMapper formatMapper(Object setting, StrategySelector selector, Callable<FormatMapper> defaultResolver) {
return selector.resolveDefaultableStrategy( FormatMapper.class, setting, defaultResolver );
private static FormatMapper formatMapper(Object setting, StrategySelector selector, Callable<FormatMapper> defaultResolver, FormatMapperCreationContext creationContext) {
return selector.resolveStrategy( FormatMapper.class, setting, defaultResolver, strategyClass -> {
try {
final Constructor<? extends FormatMapper> creationContextConstructor =
strategyClass.getDeclaredConstructor( FormatMapperCreationContext.class );
return creationContextConstructor.newInstance( creationContext );
}
catch (NoSuchMethodException e) {
// Ignore
}
catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
throw new StrategySelectionException(
String.format( "Could not instantiate named strategy class [%s]", strategyClass.getName() ),
e
);
}
try {
return strategyClass.getDeclaredConstructor().newInstance();
}
catch (Exception e) {
throw new StrategySelectionException(
String.format( "Could not instantiate named strategy class [%s]", strategyClass.getName() ),
e
);
}
} );
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.type.format;

import org.hibernate.Incubating;
import org.hibernate.boot.spi.BootstrapContext;


/**
* The creation context for {@link FormatMapper} that is passed as constructor argument to implementations.
*/
@Incubating
public interface FormatMapperCreationContext {
BootstrapContext getBootstrapContext();

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
*/
package org.hibernate.type.format.jackson;

import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.type.format.FormatMapper;
import org.hibernate.type.format.FormatMapperCreationContext;

public final class JacksonIntegration {

Expand All @@ -13,10 +15,6 @@ public final class JacksonIntegration {
private static final boolean JACKSON_XML_AVAILABLE = ableToLoadJacksonXMLMapper();
private static final boolean JACKSON_JSON_AVAILABLE = ableToLoadJacksonJSONMapper();
private static final boolean JACKSON_OSON_AVAILABLE = ableToLoadJacksonOSONFactory();
private static final FormatMapper XML_FORMAT_MAPPER = JACKSON_XML_AVAILABLE ? new JacksonXmlFormatMapper() : null;
private static final FormatMapper XML_FORMAT_MAPPER_PORTABLE = JACKSON_XML_AVAILABLE ? new JacksonXmlFormatMapper( false ) : null;
private static final FormatMapper JSON_FORMAT_MAPPER = JACKSON_JSON_AVAILABLE ? new JacksonJsonFormatMapper() : null;
private static final FormatMapper OSON_FORMAT_MAPPER = JACKSON_OSON_AVAILABLE ? new JacksonOsonFormatMapper() : null;


private JacksonIntegration() {
Expand All @@ -41,15 +39,67 @@ private static boolean ableToLoadJacksonOSONFactory() {
canLoad( "oracle.jdbc.provider.oson.OsonFactory" );
}

public static FormatMapper getXMLJacksonFormatMapperOrNull(boolean legacyFormat) {
return legacyFormat ? XML_FORMAT_MAPPER : XML_FORMAT_MAPPER_PORTABLE;
public static @Nullable FormatMapper getXMLJacksonFormatMapperOrNull(FormatMapperCreationContext creationContext) {
return JACKSON_XML_AVAILABLE
? createFormatMapper( "org.hibernate.type.format.jackson.JacksonXmlFormatMapper", creationContext )
: null;
}

public static FormatMapper getJsonJacksonFormatMapperOrNull() {
return JSON_FORMAT_MAPPER;
public static @Nullable FormatMapper getJsonJacksonFormatMapperOrNull(FormatMapperCreationContext creationContext) {
return JACKSON_JSON_AVAILABLE
? createFormatMapper( "org.hibernate.type.format.jackson.JacksonJsonFormatMapper", creationContext )
: null;
}
public static FormatMapper getOsonJacksonFormatMapperOrNull() {
return OSON_FORMAT_MAPPER;
public static @Nullable FormatMapper getOsonJacksonFormatMapperOrNull(FormatMapperCreationContext creationContext) {
return JACKSON_OSON_AVAILABLE
? createFormatMapper( "org.hibernate.type.format.jackson.JacksonOsonFormatMapper", creationContext )
: null;
}

public static @Nullable FormatMapper getXMLJacksonFormatMapperOrNull(boolean legacyFormat) {
if ( JACKSON_XML_AVAILABLE ) {
try {
final Class<?> formatMapperClass = JacksonIntegration.class.getClassLoader()
.loadClass( "org.hibernate.type.format.jackson.JacksonXmlFormatMapper" );
return (FormatMapper) formatMapperClass.getDeclaredConstructor( boolean.class )
.newInstance( legacyFormat );
}
catch (Exception e) {
throw new RuntimeException( "Couldn't instantiate Jackson XML FormatMapper", e );
}
}
return null;
}

public static @Nullable FormatMapper getJsonJacksonFormatMapperOrNull() {
return JACKSON_JSON_AVAILABLE
? createFormatMapper( "org.hibernate.type.format.jackson.JacksonJsonFormatMapper", null )
: null;
}
public static @Nullable FormatMapper getOsonJacksonFormatMapperOrNull() {
return JACKSON_OSON_AVAILABLE
? createFormatMapper( "org.hibernate.type.format.jackson.JacksonOsonFormatMapper", null )
: null;
}

private static FormatMapper createFormatMapper(String className, @Nullable FormatMapperCreationContext creationContext) {
try {
if ( creationContext == null ) {
final Class<?> formatMapperClass = JacksonIntegration.class.getClassLoader()
.loadClass( className );
return (FormatMapper) formatMapperClass.getDeclaredConstructor().newInstance();
}
else {
return (FormatMapper) creationContext.getBootstrapContext()
.getClassLoaderAccess()
.classForName( className )
.getDeclaredConstructor( FormatMapperCreationContext.class )
.newInstance( creationContext );
}
}
catch (Exception e) {
throw new RuntimeException( "Couldn't instantiate Jackson FormatMapper", e );
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.Module;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.format.AbstractJsonFormatMapper;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.hibernate.type.format.FormatMapperCreationContext;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.List;

/**
* @author Christian Beikov
Expand All @@ -27,7 +30,19 @@ public final class JacksonJsonFormatMapper extends AbstractJsonFormatMapper {
private final ObjectMapper objectMapper;

public JacksonJsonFormatMapper() {
this( new ObjectMapper().findAndRegisterModules() );
this( ObjectMapper.findModules( JacksonJsonFormatMapper.class.getClassLoader() ) );
}

public JacksonJsonFormatMapper(FormatMapperCreationContext creationContext) {
this(
creationContext.getBootstrapContext()
.getClassLoaderService()
.<List<Module>>workWithClassLoader( ObjectMapper::findModules )
);
}

private JacksonJsonFormatMapper(List<Module> modules) {
this( new ObjectMapper().registerModules( modules ) );
}

public JacksonJsonFormatMapper(ObjectMapper objectMapper) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import oracle.jdbc.provider.oson.OsonModule;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.format.AbstractJsonFormatMapper;
import org.hibernate.type.format.FormatMapperCreationContext;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.List;


/**
Expand All @@ -34,7 +37,19 @@ public final class JacksonOsonFormatMapper extends AbstractJsonFormatMapper {
* Creates a new JacksonOsonFormatMapper
*/
public JacksonOsonFormatMapper() {
this( new ObjectMapper().findAndRegisterModules() );
this( ObjectMapper.findModules( JacksonJsonFormatMapper.class.getClassLoader() ) );
}

public JacksonOsonFormatMapper(FormatMapperCreationContext creationContext) {
this(
creationContext.getBootstrapContext()
.getClassLoaderService()
.<List<Module>>workWithClassLoader( ObjectMapper::findModules )
);
}

private JacksonOsonFormatMapper(List<Module> modules) {
this( new ObjectMapper().registerModules( modules ) );
}

public JacksonOsonFormatMapper(ObjectMapper objectMapper) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.util.Map;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
Expand All @@ -36,6 +37,7 @@
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import org.hibernate.type.format.FormatMapperCreationContext;
import org.hibernate.type.internal.ParameterizedTypeImpl;

/**
Expand All @@ -45,7 +47,7 @@
public final class JacksonXmlFormatMapper implements FormatMapper {

public static final String SHORT_NAME = "jackson-xml";
private boolean legacyFormat;
private final boolean legacyFormat;

private final ObjectMapper objectMapper;

Expand All @@ -54,18 +56,41 @@ public JacksonXmlFormatMapper() {
}

public JacksonXmlFormatMapper(boolean legacyFormat) {
this( createXmlMapper( legacyFormat ) );
this.legacyFormat = legacyFormat;
this(
createXmlMapper( XmlMapper.findModules( JacksonXmlFormatMapper.class.getClassLoader() ), legacyFormat ),
legacyFormat
);
}

public JacksonXmlFormatMapper(FormatMapperCreationContext creationContext) {
this(
createXmlMapper(
creationContext.getBootstrapContext()
.getClassLoaderService()
.<List<Module>>workWithClassLoader( XmlMapper::findModules ),
creationContext.getBootstrapContext()
.getMetadataBuildingOptions()
.isXmlFormatMapperLegacyFormatEnabled()
),
creationContext.getBootstrapContext()
.getMetadataBuildingOptions()
.isXmlFormatMapperLegacyFormatEnabled()
);
}

public JacksonXmlFormatMapper(ObjectMapper objectMapper) {
this( objectMapper, false );
}

public JacksonXmlFormatMapper(ObjectMapper objectMapper, boolean legacyFormat) {
this.objectMapper = objectMapper;
this.legacyFormat = legacyFormat;
}

private static XmlMapper createXmlMapper(boolean legacyFormat) {
private static XmlMapper createXmlMapper(List<Module> modules, boolean legacyFormat) {
final XmlMapper xmlMapper = new XmlMapper();
// needed to automatically find and register Jackson's jsr310 module for java.time support
xmlMapper.findAndRegisterModules();
xmlMapper.registerModules( modules );
xmlMapper.configure( SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false );
xmlMapper.enable( ToXmlGenerator.Feature.WRITE_NULLS_AS_XSI_NIL );
// Workaround for null vs empty string handling inside arrays,
Expand Down
Loading