diff --git a/k2-archetype-application/pom.xml b/k2-archetype-application/pom.xml
index daa870e..54353b4 100644
--- a/k2-archetype-application/pom.xml
+++ b/k2-archetype-application/pom.xml
@@ -9,7 +9,7 @@
com.github.katari
k2-parent
- 0.1.9-SNAPSHOT
+ 0.1.13-SNAPSHOT
../k2-parent/pom.xml
diff --git a/k2-archetype-module/pom.xml b/k2-archetype-module/pom.xml
index eaf9f19..d50d7c9 100644
--- a/k2-archetype-module/pom.xml
+++ b/k2-archetype-module/pom.xml
@@ -9,7 +9,7 @@
com.github.katari
k2-parent
- 0.1.9-SNAPSHOT
+ 0.1.13-SNAPSHOT
../k2-parent/pom.xml
diff --git a/k2-build-tools/pom.xml b/k2-build-tools/pom.xml
index ef5d0a1..aa4f158 100644
--- a/k2-build-tools/pom.xml
+++ b/k2-build-tools/pom.xml
@@ -8,7 +8,7 @@
com.github.katari
k2
- 0.1.9-SNAPSHOT
+ 0.1.13-SNAPSHOT
k2-build-tools
diff --git a/k2-core/pom.xml b/k2-core/pom.xml
index 33af4ca..fec4128 100644
--- a/k2-core/pom.xml
+++ b/k2-core/pom.xml
@@ -1,3 +1,4 @@
+
@@ -9,7 +10,7 @@
com.github.katari
k2-parent
- 0.1.9-SNAPSHOT
+ 0.1.13-SNAPSHOT
../k2-parent/pom.xml
@@ -67,8 +68,8 @@
- javax.servlet
- javax.servlet-api
+ jakarta.servlet
+ jakarta.servlet-api
diff --git a/k2-core/src/main/java/com/k2/core/DispatcherServletConfiguration.java b/k2-core/src/main/java/com/k2/core/DispatcherServletConfiguration.java
index d4e760a..efd36f8 100644
--- a/k2-core/src/main/java/com/k2/core/DispatcherServletConfiguration.java
+++ b/k2-core/src/main/java/com/k2/core/DispatcherServletConfiguration.java
@@ -2,17 +2,6 @@
package com.k2.core;
-import org.springframework.web.servlet.config.annotation
- .ResourceHandlerRegistration;
-import org.springframework.web.servlet.config.annotation
- .ResourceHandlerRegistry;
-import org.springframework.web.servlet.config.annotation
- .WebMvcConfigurationSupport;
-import org.springframework.web.servlet.mvc.method.annotation
- .RequestMappingHandlerAdapter;
-import org.springframework.web.servlet.mvc.method.annotation
- .RequestMappingHandlerMapping;
-
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
@@ -20,11 +9,20 @@
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.context.support
- .PropertySourcesPlaceholderConfigurer;
+import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar;
import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.web.servlet.config.annotation
+ .ResourceHandlerRegistration;
+import org.springframework.web.servlet.config.annotation
+ .ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation
+ .WebMvcConfigurationSupport;
+import org.springframework.web.servlet.mvc.method.annotation
+ .RequestMappingHandlerAdapter;
+import org.springframework.web.servlet.mvc.method.annotation
+ .RequestMappingHandlerMapping;
/** Custom configuration for the dispatcher servlet application context
*
@@ -85,8 +83,8 @@ protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
final List> converters) {
- RequestMappingHandlerAdapter adapter;
- adapter = super.requestMappingHandlerAdapter();
+ RequestMappingHandlerAdapter adapter =
+ super.createRequestMappingHandlerAdapter();
if (!converters.isEmpty()) {
adapter.setMessageConverters(converters);
diff --git a/k2-core/src/main/java/com/k2/core/HomeServlet.java b/k2-core/src/main/java/com/k2/core/HomeServlet.java
index 8c39674..56f3105 100644
--- a/k2-core/src/main/java/com/k2/core/HomeServlet.java
+++ b/k2-core/src/main/java/com/k2/core/HomeServlet.java
@@ -4,10 +4,10 @@
import java.io.IOException;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.Validate;
import org.springframework.web.servlet.view.RedirectView;
diff --git a/k2-core/src/main/java/com/k2/core/K2WebApplicationContext.java b/k2-core/src/main/java/com/k2/core/K2WebApplicationContext.java
index 8b11207..7a9c2a4 100644
--- a/k2-core/src/main/java/com/k2/core/K2WebApplicationContext.java
+++ b/k2-core/src/main/java/com/k2/core/K2WebApplicationContext.java
@@ -7,7 +7,7 @@
import java.util.LinkedList;
import java.util.List;
-import javax.servlet.ServletContext;
+import jakarta.servlet.ServletContext;
import org.apache.commons.lang3.Validate;
diff --git a/k2-core/src/main/java/com/k2/core/ModuleDefinition.java b/k2-core/src/main/java/com/k2/core/ModuleDefinition.java
index 9e39e1c..c72f463 100644
--- a/k2-core/src/main/java/com/k2/core/ModuleDefinition.java
+++ b/k2-core/src/main/java/com/k2/core/ModuleDefinition.java
@@ -18,7 +18,7 @@
import java.beans.Introspector;
import java.lang.reflect.Method;
-import javax.servlet.ServletContext;
+import jakarta.servlet.ServletContext;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
diff --git a/k2-core/src/main/java/com/k2/core/WebConfiguration.java b/k2-core/src/main/java/com/k2/core/WebConfiguration.java
index a76d6e2..909d9a3 100644
--- a/k2-core/src/main/java/com/k2/core/WebConfiguration.java
+++ b/k2-core/src/main/java/com/k2/core/WebConfiguration.java
@@ -106,12 +106,12 @@ public void customize(final Server pServer) {
* shows a hardcoded message.
*/
@Bean(name = "k2.homeServlet")
- public ServletRegistrationBean homeServlet(
+ public ServletRegistrationBean homeServlet(
@Qualifier("k2.landingUrl") final String landingUrl) {
HomeServlet homeServlet = new HomeServlet(landingUrl);
- ServletRegistrationBean servletBean;
- servletBean = new ServletRegistrationBean(homeServlet, false, "");
+ ServletRegistrationBean servletBean;
+ servletBean = new ServletRegistrationBean<>(homeServlet, false, "");
servletBean.setOrder(Integer.MAX_VALUE);
return servletBean;
}
diff --git a/k2-core/src/test/java/com/k2/core/ApplicationTest.java b/k2-core/src/test/java/com/k2/core/ApplicationTest.java
index 02d0148..acd74ca 100644
--- a/k2-core/src/test/java/com/k2/core/ApplicationTest.java
+++ b/k2-core/src/test/java/com/k2/core/ApplicationTest.java
@@ -8,12 +8,12 @@
import java.io.IOException;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletResponse;
import org.junit.BeforeClass;
import org.junit.Test;
diff --git a/k2-hibernate/pom.xml b/k2-hibernate/pom.xml
index 4236e22..ddbdcf1 100644
--- a/k2-hibernate/pom.xml
+++ b/k2-hibernate/pom.xml
@@ -9,7 +9,7 @@
com.github.katari
k2-parent
- 0.1.9-SNAPSHOT
+ 0.1.13-SNAPSHOT
../k2-parent/pom.xml
@@ -73,8 +73,9 @@
- com.h2database
- h2
+ org.hsqldb
+ hsqldb
+ test
@@ -86,8 +87,8 @@
- javax.servlet
- javax.servlet-api
+ jakarta.servlet
+ jakarta.servlet-api
diff --git a/k2-hibernate/src/main/java/com/k2/hibernate/Hibernate.java b/k2-hibernate/src/main/java/com/k2/hibernate/Hibernate.java
index 8f21af5..6168173 100644
--- a/k2-hibernate/src/main/java/com/k2/hibernate/Hibernate.java
+++ b/k2-hibernate/src/main/java/com/k2/hibernate/Hibernate.java
@@ -2,45 +2,47 @@
package com.k2.hibernate;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.HashMap;
-import java.util.Iterator;
import org.apache.commons.lang3.Validate;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.PropertySource;
-import org.springframework.orm.hibernate5.HibernateTransactionManager;
-import org.springframework.stereotype.Component;
-
import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolProperties;
-import org.hibernate.EntityMode;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataBuilder;
import org.hibernate.boot.MetadataSources;
+import org.hibernate.boot.internal.BootstrapContextImpl;
+import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.ForeignKey;
import org.hibernate.mapping.MetaAttribute;
import org.hibernate.mapping.PersistentClass;
-import org.hibernate.mapping.Property;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.Table.ForeignKeyKey;
import org.hibernate.mapping.UniqueKey;
+import org.hibernate.metamodel.spi.ManagedTypeRepresentationResolver;
import org.hibernate.service.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.orm.hibernate5.HibernateTransactionManager;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ReflectionUtils;
import com.k2.core.K2Environment;
-import com.k2.core.RegistryFactory;
import com.k2.core.ModuleDefinition;
import com.k2.core.Public;
+import com.k2.core.RegistryFactory;
/** The hibernate module.
*
@@ -69,11 +71,15 @@
*
* The module reads the following properties:
*
- * hibernate.k2.usePrefix: if true, adds the module short name to each table
- * and foreign key name. Defaults to true.
+ * hibernate.k2.namingStrategy the fully qualified class name of the naming
+ * strategy to use. If null, it complies with the hibernate.k2.useK2Naming
+ * attribute.
*
* hibernate.k2.useK2Naming: if true, uses the k2 database naming convention:
* all lower case, underscore separated.
+ *
+ * hibernate.k2.usePrefix: if true, adds the module short name to each table
+ * and foreign key name. Defaults to true.
*/
@Component("hibernate")
@PropertySource("classpath:/com/k2/hibernate/hibernate.properties")
@@ -122,8 +128,11 @@ public HibernateTransactionManager transactionManager(
* @param environment the environment provided by k2 core, used by hibernate
* to obtain its properties.
*
+ * @param implicitNamingStrategy the fully qualified class name of the naming
+ * strategy to use. If null, it complies with the useK2Naming attribute.
+ *
* @param useK2Naming true to use the k2 database naming conventions. False
- * uses hibernate default.
+ * uses hibernate default. Ignored if implicitNamingStrategy is set.
*
* @param usePrefix true to add the module short name as a prefix to each
* database object. Defaults to true.
@@ -134,6 +143,8 @@ public HibernateTransactionManager transactionManager(
*/
@Bean public Metadata metadata(
final K2Environment environment,
+ @Value("${hibernate.k2.namingStrategy:#{null}}")
+ final String implicitNamingStrategy,
@Value("${hibernate.k2.useK2Naming:#{true}}") final boolean useK2Naming,
@Value("${hibernate.k2.usePrefix:#{true}}") final boolean usePrefix,
final DataSource dataSource) {
@@ -142,10 +153,12 @@ public HibernateTransactionManager transactionManager(
.applySetting("hibernate.current_session_context_class",
"org.springframework.orm.hibernate5.SpringSessionContext")
.applySettings(environment.getProperties("hibernate"))
- .addService(this.getClass(), new HibernateRegistryLocator(registries))
+ .addService(HibernateRegistryLocator.class,
+ new HibernateRegistryLocator(registries))
.build();
- // Collects the entity prefixes from the hibernate registries.
+ // Collects the entity prefixes from the hibernate registries. This maps a
+ // fully qualified class name to the k2 module short name.
Map, String> prefixes = new HashMap<>();
MetadataSources metadataSources = new MetadataSources(registry);
for (HibernateRegistry hibernateRegistry: registries) {
@@ -156,12 +169,30 @@ public HibernateTransactionManager transactionManager(
}
// Builds the hibernate metadata.
- MetadataBuilder metadataBuilder = metadataSources.getMetadataBuilder()
- .enableNewIdentifierGeneratorSupport(false);
- if (useK2Naming) {
+ MetadataBuilder metadataBuilder = metadataSources.getMetadataBuilder();
+ if (implicitNamingStrategy != null) {
+ ImplicitNamingStrategy namingStrategy;
+ try {
+ Class extends ImplicitNamingStrategy> type;
+ type = Class.forName(implicitNamingStrategy)
+ .asSubclass(ImplicitNamingStrategy.class);
+ namingStrategy = type.newInstance();
+ } catch (InstantiationException | IllegalAccessException
+ | ClassNotFoundException e) {
+ throw new RuntimeException(
+ "Error instantiating class " + implicitNamingStrategy, e);
+ }
+ metadataBuilder.applyImplicitNamingStrategy(namingStrategy);
+ } else if (useK2Naming) {
metadataBuilder.applyImplicitNamingStrategy(
new K2DbImplicitNamingStrategy());
}
+ for (HibernateRegistry hibernateRegistry: registries) {
+ for (Class converter : hibernateRegistry.getConverters()) {
+ metadataBuilder.applyAttributeConverter(converter, true);
+ }
+ }
+
Metadata metadata = metadataBuilder.build();
// This map contains the full list of tables and the prefix to add to their
@@ -195,8 +226,6 @@ public HibernateTransactionManager transactionManager(
tablePrefixes.put(table, prefix);
}
- configureTuplizers(pc);
-
MetaAttribute attribute = new MetaAttribute("k2.moduleContext");
Map attributes = new HashMap<>();
attributes.put("k2.moduleContext", attribute);
@@ -210,54 +239,9 @@ public HibernateTransactionManager transactionManager(
}
}
- return metadata;
- }
-
- /** Configures the tuplizers for the persistent class and its referenced
- * components.
- *
- * @param pc the persistent class to look for components. It cannot be null.
- */
- @SuppressWarnings("unchecked")
- private void configureTuplizers(final PersistentClass pc) {
-
- pc.addTuplizer(EntityMode.POJO, HibernateEntityTuplizer.class.getName());
+ configureManageTypeRepresentationResolver(metadata);
- configureComponentTuplizers(pc.getPropertyIterator());
- }
-
- /** Configures the tuplizers for all component properties in the iterator.
- *
- * @param propertyIterator the property iterator. It cannot be null.
- */
- @SuppressWarnings("unchecked")
- private void configureComponentTuplizers(
- final Iterator propertyIterator) {
-
- while (propertyIterator.hasNext()) {
- Property property = propertyIterator.next();
- org.hibernate.mapping.Value value = property.getValue();
-
- if (value instanceof Collection) {
- value = ((Collection) value).getElement();
- }
-
- if (value instanceof org.hibernate.mapping.Component) {
- org.hibernate.mapping.Component component =
- (org.hibernate.mapping.Component) value;
-
- if (component.getTuplizerImplClassName(EntityMode.POJO) == null) {
- // Tuplizer not yet configured for this component.
- component.addTuplizer(EntityMode.POJO,
- HibernateComponentTuplizer.class.getName());
- configureComponentTuplizers(component.getPropertyIterator());
- }
-
- } else {
- log.warn("Type of value is {}, not configuring tuplizer.",
- value.getClass());
- }
- }
+ return metadata;
}
/** Renames the table and its related elements based on the module prefix.
@@ -286,6 +270,60 @@ private void prefixDddlElements(final Table table, final String prefix) {
}
}
+ /** Configures a custom ManagedTypeRepresentationResolver to customize
+ * hibernate instantiation of entities and components through Factories.
+ *
+ * @param metadata The hibernates' metadata. Cannot be null.
+ * Cannot be null.
+ */
+ private void configureManageTypeRepresentationResolver(
+ final Metadata metadata) {
+ BootstrapContextImpl context = getField(metadata, "bootstrapContext");
+ ManagedTypeRepresentationResolver originalRepresentationResolver =
+ getField(context, "representationStrategySelector");
+
+ K2ManagedTypeRepresentationResolver customResolver =
+ new K2ManagedTypeRepresentationResolver(originalRepresentationResolver);
+ for (HibernateRegistry hibernateRegistry : registries) {
+ customResolver.registerHibernateRegistry(hibernateRegistry);
+ }
+ setField(context, "representationStrategySelector", customResolver);
+ }
+
+ /** Reflection helper method that injects a value into field in the target
+ * object.
+ *
+ * @param target The target object. Cannot be null.
+ *
+ * @param fieldName that must be present in the target object.
+ * Cannot be null.
+ *
+ * @param newValue The value to be set in the target field.
+ */
+ private void setField(final Object target, final String fieldName,
+ final Object newValue) {
+ Field field = ReflectionUtils.findField(target.getClass(), fieldName);
+ field.setAccessible(true);
+ ReflectionUtils.setField(field, target, newValue);
+ }
+
+ /** Gets a field from an object by reflection.
+ *
+ * @param object from which the field must be gotten. Cannot be null.
+ *
+ * @param fieldName that must be present in the target object.
+ * Cannot be blank.
+ *
+ * @return the value hold in the field.
+ *
+ * @param The return type to avoid casts.
+ */
+ private T getField(final Object object, final String fieldName) {
+ Field field = ReflectionUtils.findField(object.getClass(), fieldName);
+ field.setAccessible(true);
+ return (T) ReflectionUtils.getField(field, object);
+ }
+
/** Hibernate SessionFactory.
*
* @param metadata the hibernate metadata, initialized with hibernate
@@ -322,17 +360,6 @@ public DataSource dataSource(final PoolProperties poolProperties) {
return new DataSource(poolProperties);
}
- /** Bean to generate the schema based on hibernate configuration.
- *
- * @param metadata the properly initialized hibernate metadata. It cannot be
- * null.
- *
- * @return an instance of SchemaGenerator, never null.
- */
- @Bean SchemaGenerator schema(final Metadata metadata) {
- return new SchemaGenerator(metadata);
- }
-
/** A hibernate service that exposes the hibernate module registries to the
* hibernate tuplizers.
*/
diff --git a/k2-hibernate/src/main/java/com/k2/hibernate/HibernateComponentTuplizer.java b/k2-hibernate/src/main/java/com/k2/hibernate/HibernateComponentTuplizer.java
deleted file mode 100644
index 0fba018..0000000
--- a/k2-hibernate/src/main/java/com/k2/hibernate/HibernateComponentTuplizer.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/* vim: set et ts=2 sw=2 cindent fo=qroca: */
-
-package com.k2.hibernate;
-
-import java.util.List;
-
-import java.lang.reflect.Method;
-import org.springframework.beans.DirectFieldAccessor;
-import org.springframework.util.ReflectionUtils;
-
-import org.apache.commons.lang3.Validate;
-import org.hibernate.bytecode.spi.ReflectionOptimizer;
-import org.hibernate.bytecode.spi.ReflectionOptimizer.InstantiationOptimizer;
-import org.hibernate.mapping.Component;
-import org.hibernate.tuple.PojoInstantiator;
-import org.hibernate.tuple.component.PojoComponentTuplizer;
-
-/** K2 hibernate tuplizer that uses module provided factories to create
- * component instances.
- *
- * See HibernateRegistry for more information.
- *
- * Note: this class is almost identical to HibernateEntityTuplizer. Look at
- * that class if you modify anything here.
- */
-@SuppressWarnings("serial")
-public class HibernateComponentTuplizer extends PojoComponentTuplizer {
-
- /** The list of registries with the entity/component classes and factories
- * provided by other modules, never null.
- */
- private List registries;
-
- /** A copy of the reflection optimizer obtained from the parent class, via
- * reflection, null if it is null in the parent class.
- */
- private ReflectionOptimizer reflectionOptimizer;
-
- /** Constructor, creates a hibernate tuplizer.
- *
- * @param component the component to instantian, as passed by
- * hibernate. This is never null.
- */
- public HibernateComponentTuplizer(final Component component) {
- super(component);
-
- registries = component.getServiceRegistry()
- .getService(Hibernate.HibernateRegistryLocator.class).getRegistries();
-
- // Hack to obtain the superclass configured reflection optimizer.
- DirectFieldAccessor fieldAccessor = new DirectFieldAccessor(this);
- reflectionOptimizer = (ReflectionOptimizer) fieldAccessor.getPropertyValue(
- "optimizer");
- }
-
- /** Overriden to use our own instantiator (see Instantiator).
- *
- * {@inheritDoc}.*/
- @Override
- protected Instantiator buildInstantiator(final Component component) {
- InstantiationOptimizer optimizer = null;
- if (reflectionOptimizer != null) {
- optimizer = reflectionOptimizer.getInstantiationOptimizer();
- }
- return new Instantiator(this, component, optimizer);
- }
-
- /** An instantiator implementation that delegates to the module provided
- * factory if it defined one.
- */
- public static class Instantiator extends PojoInstantiator {
-
- /** The hibernate tuplizer, never null. */
- private transient HibernateComponentTuplizer tuplizer;
-
- /** The component to instantiate, never null. */
- private Component component;
-
- /** Caches the factory object that will instantiate the component.
- *
- * Initially null, initialized in getFactoryMethod if the component
- * is constructed by a factory.
- */
- private Object factoryObject = null;
-
- /** Caches the factory method that will instantiate the component.
- *
- * Initially null, initialized in getFactoryMethod if the component
- * is constructed by a factory.
- */
- private Method factoryMethod = null;
-
- /** Constructor, creates an instance of the instantiator.
- *
- * @param theTuplizer the hibernate tuplizer. This instantiator looks
- * in the registries provided by this tuplizer for the factory to create
- * new instances of the persistent class. This is never null.
- *
- * @param theComponent the component to instantiate, as passed to the
- * tuplizer by hibernate. It is never null.
- *
- * @param optimizer the instantiator optimizer, obtained from the
- * reflectionOptimizer. Null if none provided by the reflection optimizer.
- */
- public Instantiator(final HibernateComponentTuplizer theTuplizer,
- final Component theComponent,
- final InstantiationOptimizer optimizer) {
- super(theComponent, optimizer);
- Validate.notNull(theTuplizer, "The tuplizer cannot be null");
- tuplizer = theTuplizer;
- component = theComponent;
- }
-
- /** Creates an instance of the component.
- *
- * This implementation looks for the factory registered in one of the
- * HibernateRegistries and calls the parameterless create operation. If
- * the module did not defined a factory for that class, it delegates to
- * the default hibernate instantiator.
- *
- * {@inheritDoc}.*/
- @Override
- public Object instantiate() {
- Method create = getFactoryMethod();
- if (create != null) {
- return ReflectionUtils.invokeMethod(create, factoryObject);
- } else {
- return super.instantiate();
- }
- }
-
- /** Obtains the factory method.
- *
- * @return a method or null if this component is not created by a factory.
- */
- synchronized
- private Method getFactoryMethod() {
- if (factoryMethod == null) {
- for (HibernateRegistry registry : tuplizer.registries) {
- factoryObject = registry.getFactoryFor(
- component.getComponentClass());
- if (factoryObject != null) {
- factoryMethod = ReflectionUtils.findMethod(
- factoryObject.getClass(), "create");
- factoryMethod.setAccessible(true);
- break;
- }
- }
- }
- return factoryMethod;
- }
- }
-}
-
diff --git a/k2-hibernate/src/main/java/com/k2/hibernate/HibernateEntityTuplizer.java b/k2-hibernate/src/main/java/com/k2/hibernate/HibernateEntityTuplizer.java
deleted file mode 100644
index 31ee173..0000000
--- a/k2-hibernate/src/main/java/com/k2/hibernate/HibernateEntityTuplizer.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/* vim: set et ts=2 sw=2 cindent fo=qroca: */
-
-package com.k2.hibernate;
-
-import java.util.List;
-
-import java.lang.reflect.Method;
-import org.springframework.beans.DirectFieldAccessor;
-import org.springframework.util.ReflectionUtils;
-
-import org.apache.commons.lang3.Validate;
-import org.hibernate.bytecode.spi.ReflectionOptimizer;
-import org.hibernate.bytecode.spi.ReflectionOptimizer.InstantiationOptimizer;
-import org.hibernate.mapping.PersistentClass;
-import org.hibernate.tuple.entity.EntityMetamodel;
-import org.hibernate.tuple.entity.PojoEntityInstantiator;
-import org.hibernate.tuple.entity.PojoEntityTuplizer;
-
-/** K2 hibernate tuplizer that uses module provided factories to create
- * entity instances.
- *
- * See HibernateRegistry for more information.
- *
- * Note: this class is almost identical to HibernateComponentTuplizer. Look at
- * that class if you modify anything here.
- */
-public class HibernateEntityTuplizer extends PojoEntityTuplizer {
-
- /** The list of registries with the entity classes and factories provided
- * by other modules, never null.
- */
- private List registries;
-
- /** A copy of the reflection optimizer obtained from the parent class, via
- * reflection, null if it is null in the parent class.
- */
- private ReflectionOptimizer reflectionOptimizer;
-
- /** Constructor, creates a hibernate tuplizer.
- *
- * @param entityMetamodel the entity metamodel as passed by hibernate, never
- * null.
- *
- * @param mappedEntity the persistent class to instantian, as passed by
- * hibernate. This is never null.
- */
- public HibernateEntityTuplizer(final EntityMetamodel entityMetamodel,
- final PersistentClass mappedEntity) {
- super(entityMetamodel, mappedEntity);
-
- registries = entityMetamodel.getSessionFactory().getServiceRegistry()
- .getService(Hibernate.HibernateRegistryLocator.class).getRegistries();
-
- // Hack to obtain the superclass configured reflection optimizer.
- DirectFieldAccessor fieldAccessor = new DirectFieldAccessor(this);
- reflectionOptimizer = (ReflectionOptimizer) fieldAccessor.getPropertyValue(
- "optimizer");
- }
-
- /** Overriden to use our own instantiator (see Instantiator).
- *
- * {@inheritDoc}.*/
- @Override
- protected Instantiator buildInstantiator(final EntityMetamodel metamodel,
- final PersistentClass persistentClass) {
- InstantiationOptimizer optimizer = null;
- if (reflectionOptimizer != null) {
- optimizer = reflectionOptimizer.getInstantiationOptimizer();
- }
- return new Instantiator(this, metamodel, persistentClass, optimizer);
- }
-
- /** An instantiator implementation that delegates to the module provided
- * factory if it defined one.
- */
- @SuppressWarnings("serial")
- public static class Instantiator extends PojoEntityInstantiator {
-
- /** The hibernate tuplizer, never null. */
- private transient HibernateEntityTuplizer tuplizer;
-
- /** The persistent class to instantiate, never null. */
- private PersistentClass persistentClass;
-
- /** Caches the factory object that will instantiate the component.
- *
- * Initially null, initialized in getFactoryMethod if the component
- * is constructed by a factory.
- */
- private Object factoryObject = null;
-
- /** Caches the factory method that will instantiate the component.
- *
- * Initially null, initialized in getFactoryMethod if the component
- * is constructed by a factory.
- */
- private Method factoryMethod = null;
-
- /** Constructor, creates an instance of the instantiator.
- *
- * @param theTuplizer the hibernate tuplizer. This instantiator looks
- * in the registries provided by this tuplizer for the factory to create
- * new instances of the persistent class. This is never null.
- *
- * @param entityMetamodel the entity metamodel, as pass to the tuplizer by
- * hibernate. It is never null.
- *
- * @param thePersistentClass the class to instantiate, as pass to the
- * tuplizer by hibernate. It is never null.
- *
- * @param optimizer the instantiator optimizer, obtained from the
- * reflectionOptimizer. Null if none provided by the reflection optimizer.
- */
- public Instantiator(final HibernateEntityTuplizer theTuplizer,
- final EntityMetamodel entityMetamodel,
- final PersistentClass thePersistentClass,
- final InstantiationOptimizer optimizer) {
- super(entityMetamodel, thePersistentClass, optimizer);
- Validate.notNull(theTuplizer, "The tuplizer cannot be null");
- tuplizer = theTuplizer;
- persistentClass = thePersistentClass;
- }
-
- /** Creates an instance of the persistent class.
- *
- * This implementation looks for the factory registered in one of the
- * HibernateRegistries and calls the parameterless create operation. If
- * the module did not defined a factory for that class, it delegates to
- * the default hibernate instantiator.
- *
- * {@inheritDoc}.*/
- @Override
- public Object instantiate() {
- Method create = getFactoryMethod();
- if (create != null) {
- return ReflectionUtils.invokeMethod(create, factoryObject);
- } else {
- return super.instantiate();
- }
- }
-
- /** Obtains the factory method.
- *
- * @return a method or null if this component is not created by a factory.
- */
- synchronized
- private Method getFactoryMethod() {
- if (factoryMethod == null) {
- for (HibernateRegistry registry : tuplizer.registries) {
- factoryObject = registry.getFactoryFor(
- persistentClass.getMappedClass());
- if (factoryObject != null) {
- factoryMethod = ReflectionUtils.findMethod(
- factoryObject.getClass(), "create");
- factoryMethod.setAccessible(true);
- break;
- }
- }
- }
- return factoryMethod;
- }
- }
-}
-
diff --git a/k2-hibernate/src/main/java/com/k2/hibernate/HibernateRegistry.java b/k2-hibernate/src/main/java/com/k2/hibernate/HibernateRegistry.java
index c862eff..0aa0df8 100644
--- a/k2-hibernate/src/main/java/com/k2/hibernate/HibernateRegistry.java
+++ b/k2-hibernate/src/main/java/com/k2/hibernate/HibernateRegistry.java
@@ -7,6 +7,8 @@
import java.util.Map;
import java.util.HashMap;
+import jakarta.persistence.AttributeConverter;
+
import org.apache.commons.lang3.Validate;
import com.k2.core.ModuleDefinition;
@@ -56,9 +58,19 @@ public class HibernateRegistry {
* for instantiating entities.
*
* Hibernate looks for an operation named 'create' with no arguments.
+ *
+ * This is never null.
*/
private Map, Class>> factories = new HashMap<>();
+ /** The attribute converters that converts entity attribute state
+ * into the database column representation and back again.
+ *
+ * This is never null.
+ */
+ private List>> converters
+ = new LinkedList<>();
+
/** Constructor, creates a hibernate registry.
*
* @param theRequestor the definition of the module registering persistent
@@ -95,6 +107,18 @@ public void registerPersistentClass(final Class> theClass,
factories.put(theClass, factory);
}
+ /** Registers an attribute converter that converts entity attribute state
+ * into the database column representation and back again.
+ *
+ * See AttributeConverter on ways to use this feature.
+ *
+ * @param converter the converter to register. It cannot be null.
+ */
+ public void registerConverter(
+ final Class extends AttributeConverter, ?>> converter) {
+ converters.add(converter);
+ }
+
/** Returns the list of persistent classes.
*
* @return the persistent classes, never returns null.
@@ -103,6 +127,14 @@ List> getPersistentClasses() {
return persistentClasses;
}
+ /** Returns the list of converters.
+ *
+ * @return the converters, never returns null.
+ */
+ List>> getConverters() {
+ return converters;
+ }
+
/** Returns the factory to create a new instance of persistentClass.
*
* @param persistentClass the type of the instance to create. It cannot be
@@ -119,6 +151,18 @@ Object getFactoryFor(final Class> persistentClass) {
return null;
}
+ /** Indicates if the persistent class was registered with a factory.
+ *
+ * @param persistentClass to be verified. Cannot be null.
+ *
+ * @return true if the persistent class was registered with a factory,
+ * false otherwise.
+ */
+ boolean hasFactoryFor(final Class> persistentClass) {
+ Validate.notNull(persistentClass, "The PersistentClass cannot be null.");
+ return factories.containsKey(persistentClass);
+ }
+
/** Returns the prefix to use to create tables in the database that
* will store the persisent instances of the module.
*
diff --git a/k2-hibernate/src/main/java/com/k2/hibernate/K2ComponentInstantiator.java b/k2-hibernate/src/main/java/com/k2/hibernate/K2ComponentInstantiator.java
new file mode 100644
index 0000000..14af9e3
--- /dev/null
+++ b/k2-hibernate/src/main/java/com/k2/hibernate/K2ComponentInstantiator.java
@@ -0,0 +1,80 @@
+package com.k2.hibernate;
+
+import java.lang.reflect.Method;
+
+import org.apache.commons.lang3.Validate;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.metamodel.spi.EmbeddableInstantiator;
+import org.hibernate.metamodel.spi.ValueAccess;
+import org.springframework.util.ReflectionUtils;
+
+/** Custom Instantiator for embeddable components.
+ *
+ * It uses a factory method instead of a default constructor when hibernate
+ * retrieves objects from the db.
+ *
+ * This way, clients can retrieve objects with services injected.
+ */
+public class K2ComponentInstantiator implements EmbeddableInstantiator {
+
+ /** The class of the component that will be instantiated. Never null. */
+ private final Class> componentClass;
+
+ /** The hibernate registry in which the component was registered to.
+ * Never null. */
+ private final HibernateRegistry hibernateRegistry;
+
+ /** The Factory that will handle instantiaton through a factory method.
+ * It's null until lazily initiated. */
+ private Object factory;
+
+ /** The factory method that will handle instantiaton.
+ * It's null until lazily initiated. */
+ private Method factoryMethod;
+
+ /** Constructor.
+ *
+ * @param theComponentClass the class of the component that will be
+ * instantiated. Cannot be null.
+ *
+ * @param theHibernateRegistry in which the components' factory was
+ * registered to. Cannot be null.
+ */
+ public K2ComponentInstantiator(final Class> theComponentClass,
+ final HibernateRegistry theHibernateRegistry) {
+ Validate.notNull(theComponentClass,
+ "The ComponentClass cannot be null.");
+ Validate.notNull(theHibernateRegistry,
+ "The HibernateRegistry cannot be null.");
+ componentClass = theComponentClass;
+ hibernateRegistry = theHibernateRegistry;
+ }
+
+ @Override
+ public Object instantiate(
+ final ValueAccess valueAccess,
+ final SessionFactoryImplementor sessionFactoryImpl) {
+ if (factory == null) {
+ // Lazy-init to delay the process until all factory beans are initialized.
+ factory = hibernateRegistry.getFactoryFor(componentClass);
+ factoryMethod = ReflectionUtils.findMethod(factory.getClass(), "create");
+ factoryMethod.setAccessible(true);
+ }
+ return ReflectionUtils.invokeMethod(factoryMethod, factory);
+ }
+
+ @Override
+ public boolean isInstance(
+ final Object theO,
+ final SessionFactoryImplementor theSessionFactoryImplementor) {
+ return componentClass.isInstance(theO);
+ }
+
+ @Override
+ public boolean isSameClass(
+ final Object theO,
+ final SessionFactoryImplementor theSessionFactoryImplementor) {
+ return theO.getClass().equals(componentClass);
+ }
+
+}
diff --git a/k2-hibernate/src/main/java/com/k2/hibernate/K2DbImplicitNamingStrategy.java b/k2-hibernate/src/main/java/com/k2/hibernate/K2DbImplicitNamingStrategy.java
index 3db86b2..a28e914 100644
--- a/k2-hibernate/src/main/java/com/k2/hibernate/K2DbImplicitNamingStrategy.java
+++ b/k2-hibernate/src/main/java/com/k2/hibernate/K2DbImplicitNamingStrategy.java
@@ -27,6 +27,7 @@
import org.hibernate.boot.model.naming.ImplicitPrimaryKeyJoinColumnNameSource;
import org.hibernate.boot.model.naming.ImplicitTenantIdColumnNameSource;
import org.hibernate.boot.model.naming.ImplicitUniqueKeyNameSource;
+import org.hibernate.boot.spi.MetadataBuildingContext;
import org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy;
/** A k2 provided implicit naming strategy that mainly converts java camel case
@@ -47,6 +48,12 @@
*/
public class K2DbImplicitNamingStrategy implements ImplicitNamingStrategy {
+ /** The max identifier length for fk and unique indexes.
+ *
+ * This max length accounts for a module short name of max 3 characters.
+ */
+ private static final int MAX_LENGTH = 60;
+
/** The base implementation of this naming strategy, never null. */
private ImplicitNamingStrategy delegate;
@@ -77,6 +84,23 @@ public Identifier determineJoinTableName(
return apply(delegate.determineJoinTableName(source));
}
+ /** Easy hook to build an Identifier using the keyword safe IdentifierHelper.
+ *
+ * @param stringForm The String form of the name
+ *
+ * @param buildingContext Access to the IdentifierHelper
+ *
+ * @return The identifier
+ */
+ Identifier toIdentifier(final String stringForm,
+ final MetadataBuildingContext buildingContext) {
+ return buildingContext.getMetadataCollector()
+ .getDatabase()
+ .getJdbcEnvironment()
+ .getIdentifierHelper()
+ .toIdentifier(stringForm);
+ }
+
@Override
public Identifier determineCollectionTableName(
final ImplicitCollectionTableNameSource source) {
@@ -145,20 +169,36 @@ public Identifier determineListIndexColumnName(
/** Creates a foreign key name concatenating "fk", the table name and the
* list of columns of the table in alphabetical order, all separated by '_'.
+ *
+ * It uses the user provided identifier, if any.
*/
@Override
public Identifier determineForeignKeyName(
final ImplicitForeignKeyNameSource source) {
- StringBuilder fkName = new StringBuilder();
- fkName.append("fk_");
- fkName.append(source.getTableName().getText());
- for (Identifier columnName : sort(source.getColumnNames())) {
- fkName.append("_").append(columnName.getText());
+ Identifier result = source.getUserProvidedIdentifier();
+ if (result == null) {
+ StringBuilder fkName = new StringBuilder();
+
+ fkName.append("fk_");
+ fkName.append(source.getTableName().getText());
+ for (Identifier columnName : sort(source.getColumnNames())) {
+ fkName.append("_").append(columnName.getText());
+ }
+
+ if (fkName.length() <= MAX_LENGTH) {
+ result = apply(source.getBuildingContext().getObjectNameNormalizer()
+ .normalizeIdentifierQuoting(toIdentifier(fkName.toString(),
+ source.getBuildingContext())));
+ } else {
+ String name = delegate.determineForeignKeyName(source).getText();
+
+ result = source.getBuildingContext().getObjectNameNormalizer()
+ .normalizeIdentifierQuoting(toIdentifier("fk_" + name,
+ source.getBuildingContext()));
+ }
}
- return apply(source.getBuildingContext().getObjectNameNormalizer()
- .normalizeIdentifierQuoting(Identifier.toIdentifier(
- fkName.toString())));
+ return result;
}
/** Creates a unique key name concatenating "uk" and the list of columns of
@@ -167,15 +207,25 @@ public Identifier determineForeignKeyName(
@Override
public Identifier determineUniqueKeyName(
final ImplicitUniqueKeyNameSource source) {
- StringBuilder fkName = new StringBuilder();
- fkName.append("uk_");
- fkName.append(source.getTableName());
+ StringBuilder ukName = new StringBuilder();
+ ukName.append("uk_");
+ ukName.append(source.getTableName());
for (Identifier columnName : source.getColumnNames()) {
- fkName.append("_").append(columnName.getText());
+ ukName.append("_").append(columnName.getText());
}
- return apply(source.getBuildingContext().getObjectNameNormalizer()
- .normalizeIdentifierQuoting(Identifier.toIdentifier(
- fkName.toString())));
+ Identifier result;
+
+ if (ukName.length() <= MAX_LENGTH) {
+ result = apply(source.getBuildingContext().getObjectNameNormalizer()
+ .normalizeIdentifierQuoting(toIdentifier(ukName.toString(),
+ source.getBuildingContext())));
+ } else {
+ String name = delegate.determineUniqueKeyName(source).getText();
+ result = source.getBuildingContext().getObjectNameNormalizer()
+ .normalizeIdentifierQuoting(toIdentifier("uk_" + name,
+ source.getBuildingContext()));
+ }
+ return result;
}
/** Creates an index name concatenating "idx" and the list of columns of the
@@ -191,15 +241,15 @@ public Identifier determineIndexName(final ImplicitIndexNameSource source) {
}
return apply(source.getBuildingContext().getObjectNameNormalizer()
- .normalizeIdentifierQuoting(Identifier.toIdentifier(
- fkName.toString())));
+ .normalizeIdentifierQuoting(toIdentifier(fkName.toString(),
+ source.getBuildingContext())));
}
/** Alphabetically sorts a list of identifiers.
*
* @param identifiers the list of identifiers to sort. It cannot be null.
*
- * @return a new arry with the identifiers alphabetically sorted. Never
+ * @return a new array with the identifiers alphabetically sorted. Never
* returns null.
*/
private Identifier[] sort(final List identifiers) {
@@ -245,7 +295,7 @@ public int compare(final Identifier o1, final Identifier o2) {
* @return a name converted form camel case to underscore separated words. It
* never returns null.
*/
- private Identifier apply(final Identifier name) {
+ protected Identifier apply(final Identifier name) {
LinkedList result = new LinkedList<>();
String nameText = name.getText();
for (String part : StringUtils.splitByCharacterTypeCamelCase(nameText)) {
diff --git a/k2-hibernate/src/main/java/com/k2/hibernate/K2DbImplicitNamingStrategyComponentPath.java b/k2-hibernate/src/main/java/com/k2/hibernate/K2DbImplicitNamingStrategyComponentPath.java
new file mode 100644
index 0000000..0e36a95
--- /dev/null
+++ b/k2-hibernate/src/main/java/com/k2/hibernate/K2DbImplicitNamingStrategyComponentPath.java
@@ -0,0 +1,155 @@
+/* vim: set et ts=2 sw=2 cindent fo=qroca: */
+
+package com.k2.hibernate;
+
+import java.lang.reflect.Field;
+
+import org.apache.commons.lang3.Validate;
+import org.apache.commons.lang3.tuple.Pair;
+import org.hibernate.boot.model.naming.Identifier;
+import org.hibernate.boot.model.naming.ImplicitBasicColumnNameSource;
+import org.hibernate.boot.model.naming.ImplicitEntityNameSource;
+import org.hibernate.boot.model.naming.ImplicitJoinTableNameSource;
+import org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl;
+import org.hibernate.boot.model.source.spi.AttributePath;
+import org.hibernate.boot.spi.MetadataBuildingContext;
+
+/** A naming strategy that uses full composite paths extracted from
+ * AttributePath, as opposed to just the terminal property part.
+ *
+ * This naming strategy supports the annotation @Prefix to customize the prefix
+ * to use for the embedded column names.
+ */
+public class K2DbImplicitNamingStrategyComponentPath
+ extends K2DbImplicitNamingStrategy {
+
+ /** The current entity class being processed.
+ *
+ * This is a hack: we are depending on an implementation detail of the
+ * client: determinePrimaryTableName will be called first, then all the
+ * necessary determineBasicColumnName for the same class, and this class is
+ * used in a single thread context.
+ */
+ private Class> currentClass = null;
+
+ /** Constructor, creates a new naming strategy.
+ */
+ K2DbImplicitNamingStrategyComponentPath() {
+ super(new ImplicitNamingStrategyComponentPathImpl());
+ }
+
+ @Override
+ public Identifier determinePrimaryTableName(
+ final ImplicitEntityNameSource source) {
+ try {
+ currentClass = Class.forName(source.getEntityNaming().getClassName());
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("Error", e);
+ }
+
+ return apply(super.determinePrimaryTableName(source));
+ }
+
+ @Override
+ public Identifier determineJoinTableName(
+ final ImplicitJoinTableNameSource source) {
+ String name = source.getOwningPhysicalTableName() + "_"
+ + source.getAssociationOwningAttributePath().getProperty();
+ return apply(toIdentifier(name, source.getBuildingContext()));
+ }
+
+ @Override
+ public Identifier determineBasicColumnName(
+ final ImplicitBasicColumnNameSource source) {
+
+ Pair prefix = getPrefix(source.getAttributePath());
+
+ String pathAsString = source.getAttributePath().getFullPath();
+
+ if (prefix.getLeft() || !prefix.getRight().equals("")) {
+ // We are asked to remove the column name prefix or replace it by a
+ // custom one. Strip the first component from the full path.
+ pathAsString = pathAsString.replaceAll("^[^.]*\\.", "");
+ }
+
+ if (!prefix.getRight().equals("")) {
+ // Add the new prefix to the path.
+ pathAsString = prefix.getRight() + "." + pathAsString;
+ }
+
+ final AttributePath path = AttributePath.parse(pathAsString);
+ Identifier result = apply(super.determineBasicColumnName(
+ new ImplicitBasicColumnNameSource() {
+ @Override
+ public MetadataBuildingContext getBuildingContext() {
+ return source.getBuildingContext();
+ }
+ @Override
+ public AttributePath getAttributePath() {
+ return path;
+ }
+ @Override
+ public boolean isCollectionElement() {
+ return source.isCollectionElement();
+ }
+ }));
+
+ return result;
+ }
+
+ /** Returns the values of the prefix annotation from the the root attribute
+ * in source.
+ *
+ * @param attributePath the attribute path from the top level entity. It
+ * cannot be null.
+ *
+ * @return a pair where the first element is true to skip the prefix from
+ * the embeddable column name, and a string with the value of the prefix.
+ * Never returns null.
+ */
+ private Pair getPrefix(final AttributePath attributePath) {
+
+ AttributePath rootAttribute = attributePath;
+ while (!rootAttribute.getParent().isRoot()) {
+ rootAttribute = rootAttribute.getParent();
+ }
+
+ Field[] fields = currentClass.getDeclaredFields();
+ Field columnField = null;
+ for (Field field : fields) {
+ if (field.getName().equals(rootAttribute.getProperty())) {
+ columnField = field;
+
+ Prefix prefix = columnField.getAnnotation(Prefix.class);
+ if (prefix != null) {
+ if (prefix.skip()) {
+ Validate.isTrue(prefix.value().equals(""),
+ "You cannot specify a prefix value when skipping the prefix");
+ }
+ return Pair.of(prefix.skip(), prefix.value());
+ } else {
+ return Pair.of(false, "");
+ }
+ }
+ }
+ return Pair.of(false, "");
+ }
+
+ /** Removes the collection_&&_element_ string in the name that appears due to
+ * ImplicitNamingStrategyComponentPathImpl.
+ *
+ * Related to HHH-6005.
+ */
+ @Override
+ protected Identifier apply(final Identifier name) {
+ String nameText = super.apply(name).getText();
+
+ if (nameText.contains("collection_&&_element_")) {
+ // This should not be necessary (see HHH-6005), but for some reason, the
+ // parent expects the dot instead of the '_'.
+ nameText = nameText.replace("collection_&&_element_", "");
+ }
+ return new Identifier(nameText, name.isQuoted());
+ }
+}
+
diff --git a/k2-hibernate/src/main/java/com/k2/hibernate/K2EmbeddableInstantiatorPojoStandard.java b/k2-hibernate/src/main/java/com/k2/hibernate/K2EmbeddableInstantiatorPojoStandard.java
new file mode 100644
index 0000000..6564834
--- /dev/null
+++ b/k2-hibernate/src/main/java/com/k2/hibernate/K2EmbeddableInstantiatorPojoStandard.java
@@ -0,0 +1,68 @@
+package com.k2.hibernate;
+
+import org.hibernate.bytecode.spi.ReflectionOptimizer;
+import org.hibernate.mapping.Property;
+import org.hibernate.metamodel.RepresentationMode;
+import org.hibernate.metamodel.spi.EmbeddableInstantiator;
+import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy;
+import org.hibernate.property.access.spi.PropertyAccess;
+import org.hibernate.type.descriptor.java.JavaType;
+
+/** A proxy class to an hibernate EmbeddableRepresentationStrategy.
+ * It handles instantiation to a custom k2 component instantiation. */
+public class K2EmbeddableInstantiatorPojoStandard
+ implements EmbeddableRepresentationStrategy {
+
+ /** The proxied embeddable representation strategy. Never null. */
+ private final EmbeddableRepresentationStrategy defaultStrategy;
+
+ /** The custom component instantiator that handles actual instantiation.
+ * Never null. */
+ private final K2ComponentInstantiator k2ComponentInstantiator;
+
+ /** Constructor.
+ *
+ * @param theDefaultStrategy the embeddable representation strategy being
+ * proxied. Cannot be null.
+ *
+ * @param hibernateRegistry required by the actual component instantiator to
+ * provide the factory method for the persistent class. Cannot be null.
+ *
+ * @param theComponentClass the class whose instantiation is being
+ * intercepted. Cannot be null.
+ *
+ */
+ public K2EmbeddableInstantiatorPojoStandard(
+ final EmbeddableRepresentationStrategy theDefaultStrategy,
+ final HibernateRegistry hibernateRegistry,
+ final Class> theComponentClass) {
+ defaultStrategy = theDefaultStrategy;
+ k2ComponentInstantiator =
+ new K2ComponentInstantiator(theComponentClass, hibernateRegistry);
+ }
+
+ @Override
+ public EmbeddableInstantiator getInstantiator() {
+ return k2ComponentInstantiator;
+ }
+
+ @Override
+ public RepresentationMode getMode() {
+ return defaultStrategy.getMode();
+ }
+
+ @Override
+ public ReflectionOptimizer getReflectionOptimizer() {
+ return defaultStrategy.getReflectionOptimizer();
+ }
+
+ @Override
+ public JavaType> getMappedJavaType() {
+ return defaultStrategy.getMappedJavaType();
+ }
+
+ @Override
+ public PropertyAccess resolvePropertyAccess(final Property theProperty) {
+ return defaultStrategy.resolvePropertyAccess(theProperty);
+ }
+}
diff --git a/k2-hibernate/src/main/java/com/k2/hibernate/K2EntityInstantiator.java b/k2-hibernate/src/main/java/com/k2/hibernate/K2EntityInstantiator.java
new file mode 100644
index 0000000..6a8a2ca
--- /dev/null
+++ b/k2-hibernate/src/main/java/com/k2/hibernate/K2EntityInstantiator.java
@@ -0,0 +1,87 @@
+package com.k2.hibernate;
+
+import java.lang.reflect.Method;
+
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.metamodel.spi.EntityInstantiator;
+import org.springframework.util.ReflectionUtils;
+
+/** Custom Instantiator for entities.
+ *
+ * It uses a factory method instead of a default constructor when hibernate
+ * retrieves objects from the db.
+ *
+ * This way, clients can retrieve objects with services injected.
+ */
+public class K2EntityInstantiator implements EntityInstantiator {
+
+ /** The class of the component that will be instantiated. Never null. */
+ private final Class> persistentClass;
+
+ /** The hibernate registry in which the component was registered to.
+ * Never null. */
+ private final HibernateRegistry hibernateRegistry;
+
+ /** The Factory that will handle instantiation through a factory method.
+ * It's null until lazily initiated. */
+ private Object factory;
+
+ /** The factory method that will handle instantiation.
+ * It's null until lazily initiated. */
+ private Method factoryMethod;
+
+ /** A flag to lazy-initialize instantiation and skip accessing the factory
+ * if not initialized yet. */
+ private boolean initialized;
+
+ /** Constructor.
+ *
+ * @param thePersistentClass the class of the component that will be
+ * instantiated. Cannot be null.
+ *
+ * @param theHibernateRegistry in which the components' factory was
+ * registered to. Cannot be null.
+ */
+ public K2EntityInstantiator(final Class> thePersistentClass,
+ final HibernateRegistry theHibernateRegistry) {
+ persistentClass = thePersistentClass;
+ hibernateRegistry = theHibernateRegistry;
+ }
+
+ @Override
+ public Object instantiate(
+ final SessionFactoryImplementor theSessionFactoryImplementor) {
+ if (factory == null) {
+ // Lazy-init to delay the process until all factory beans are initialized.
+ factory = hibernateRegistry.getFactoryFor(persistentClass);
+ factoryMethod = ReflectionUtils.findMethod(factory.getClass(), "create");
+ factoryMethod.setAccessible(true);
+ }
+ return ReflectionUtils.invokeMethod(factoryMethod, factory);
+ }
+
+ @Override
+ public boolean canBeInstantiated() {
+ // first call is forced to be false to avoid an early instantiation while
+ // we don't have the factory beans yet.
+ if (!initialized) {
+ initialized = true;
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean isInstance(
+ final Object theO,
+ final SessionFactoryImplementor theSessionFactoryImplementor) {
+ return persistentClass.isInstance(theO);
+ }
+
+ @Override
+ public boolean isSameClass(
+ final Object theO,
+ final SessionFactoryImplementor theSessionFactoryImplementor) {
+ return theO.getClass().equals(persistentClass);
+ }
+}
diff --git a/k2-hibernate/src/main/java/com/k2/hibernate/K2EntityInstantiatorPojoStandard.java b/k2-hibernate/src/main/java/com/k2/hibernate/K2EntityInstantiatorPojoStandard.java
new file mode 100644
index 0000000..3ebe83c
--- /dev/null
+++ b/k2-hibernate/src/main/java/com/k2/hibernate/K2EntityInstantiatorPojoStandard.java
@@ -0,0 +1,91 @@
+package com.k2.hibernate;
+
+import org.apache.commons.lang3.Validate;
+import org.hibernate.bytecode.spi.ReflectionOptimizer;
+import org.hibernate.mapping.Property;
+import org.hibernate.metamodel.RepresentationMode;
+import org.hibernate.metamodel.spi.EntityInstantiator;
+import org.hibernate.metamodel.spi.EntityRepresentationStrategy;
+import org.hibernate.property.access.spi.PropertyAccess;
+import org.hibernate.proxy.ProxyFactory;
+import org.hibernate.type.descriptor.java.JavaType;
+
+/** A proxy class to a EntityInstantiatorPojoStandard.
+ * It handles instantiation to a custom k2 entity instantiation. */
+public class K2EntityInstantiatorPojoStandard
+ implements EntityRepresentationStrategy {
+
+ /** The proxied entity representation strategy. Never null. */
+ private final EntityRepresentationStrategy entityRepresentationStrategy;
+
+ /** The mapped type of the persistent class. Never null. */
+ private final JavaType> mappedJavaType;
+
+ /** The custom entity instantiator that handles actual instantiation.
+ * Never null. */
+ private final K2EntityInstantiator k2EntityInstantiator;
+
+ /** Constructor.
+ *
+ * @param theEntityRepresentationStrategy the entity representation
+ * strategy being proxied. Cannot be null.
+ *
+ * @param hibernateRegistry required by the actual entity instantiator to
+ * provide the factory method for the persistent class. Cannot be null.
+ *
+ * @param persistentClass the class whose instantiation is being intercepted.
+ * Cannot be null.
+ */
+ public K2EntityInstantiatorPojoStandard(
+ final EntityRepresentationStrategy theEntityRepresentationStrategy,
+ final HibernateRegistry hibernateRegistry,
+ final Class> persistentClass) {
+ Validate.notNull(theEntityRepresentationStrategy,
+ "The EntityRepresentationStrategy cannot be null.");
+ Validate.notNull(hibernateRegistry,
+ "The HibernateRegistry cannot be null.");
+ Validate.notNull(persistentClass,
+ "The PersistentClass cannot be null.");
+
+ entityRepresentationStrategy = theEntityRepresentationStrategy;
+ mappedJavaType = entityRepresentationStrategy.getMappedJavaType();
+ k2EntityInstantiator =
+ new K2EntityInstantiator(persistentClass, hibernateRegistry);
+ }
+
+ @Override
+ public EntityInstantiator getInstantiator() {
+ return k2EntityInstantiator;
+ }
+
+ @Override
+ public ProxyFactory getProxyFactory() {
+ return entityRepresentationStrategy.getProxyFactory();
+ }
+
+ @Override
+ public JavaType> getProxyJavaType() {
+ JavaType> proxyJavaType = entityRepresentationStrategy.getProxyJavaType();
+ return proxyJavaType;
+ }
+
+ @Override
+ public RepresentationMode getMode() {
+ return RepresentationMode.POJO;
+ }
+
+ @Override
+ public ReflectionOptimizer getReflectionOptimizer() {
+ return entityRepresentationStrategy.getReflectionOptimizer();
+ }
+
+ @Override
+ public JavaType> getMappedJavaType() {
+ return mappedJavaType;
+ }
+
+ @Override
+ public PropertyAccess resolvePropertyAccess(final Property theProperty) {
+ return entityRepresentationStrategy.resolvePropertyAccess(theProperty);
+ }
+}
diff --git a/k2-hibernate/src/main/java/com/k2/hibernate/K2ManagedTypeRepresentationResolver.java b/k2-hibernate/src/main/java/com/k2/hibernate/K2ManagedTypeRepresentationResolver.java
new file mode 100644
index 0000000..3cdcaa3
--- /dev/null
+++ b/k2-hibernate/src/main/java/com/k2/hibernate/K2ManagedTypeRepresentationResolver.java
@@ -0,0 +1,125 @@
+package com.k2.hibernate;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.commons.lang3.Validate;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.metamodel.mapping.EmbeddableMappingType;
+import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy;
+import org.hibernate.metamodel.spi.EntityRepresentationStrategy;
+import org.hibernate.metamodel.spi.ManagedTypeRepresentationResolver;
+import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
+import org.hibernate.persister.entity.EntityPersister;
+
+/** Resolves the Representation Strategies for Entities and Components.
+ * It chooses a custom Representation Strategy when dealing with entities or
+ * components that need a factory instead of a default constructor on during
+ * object instantiation.
+ */
+public class K2ManagedTypeRepresentationResolver
+ implements ManagedTypeRepresentationResolver {
+
+ /** Hibernate's default ManagedTypeRepresentationResolver. Never null. */
+ private ManagedTypeRepresentationResolver hibernateTypeResolver;
+
+ /** The RepresentationStrategies for each persistent class. Never null. */
+ private Map, EntityRepresentationStrategy> strategyByEntity;
+
+ /** The representationStrategies for each embeddable. Never null. */
+ private Map, EmbeddableRepresentationStrategy> strategyByComponent;
+
+ /** The Registry where each persistent class was registered. Never null. */
+ private Map, HibernateRegistry> registryBySmartEntity;
+
+ // TODO sp 2023-08-25 Esto tendrĂa que recibir todos los beans de factories de
+ // un saque, lamentablemente para eso tienen que tener una interfaz.
+
+ /** Constructor.
+ *
+ * @param defaultRepresentationResolver Hibernates default representation
+ * resolver. Cannot be null.
+ */
+ public K2ManagedTypeRepresentationResolver(
+ final ManagedTypeRepresentationResolver defaultRepresentationResolver) {
+ Validate.notNull(defaultRepresentationResolver,
+ "The ManagedTypeRepresentationResolver cannot be null.");
+ hibernateTypeResolver = defaultRepresentationResolver;
+ strategyByEntity = new HashMap<>();
+ strategyByComponent = new HashMap<>();
+ registryBySmartEntity = new HashMap<>();
+ }
+
+ /** Registers the Hibernate registry of a k2 module.
+ *
+ * @param registry to be tracked. Cannot be null.
+ */
+ void registerHibernateRegistry(final HibernateRegistry registry) {
+ List> persistentClasses = registry.getPersistentClasses();
+ for (Class> persistentClass : persistentClasses) {
+ if (registry.hasFactoryFor(persistentClass)) {
+ registryBySmartEntity.put(persistentClass, registry);
+ }
+ }
+ }
+
+ @Override
+ public EntityRepresentationStrategy resolveStrategy(
+ final PersistentClass persistentClass,
+ final EntityPersister entityPersister,
+ final RuntimeModelCreationContext runtimeModelCreationContext) {
+
+ Class> entityClass = persistentClass.getMappedClass();
+ EntityRepresentationStrategy strategy = strategyByEntity.get(entityClass);
+ if (strategy != null) {
+ return strategy;
+ }
+
+ EntityRepresentationStrategy defaultStrategy =
+ hibernateTypeResolver.resolveStrategy(
+ persistentClass, entityPersister, runtimeModelCreationContext);
+
+ HibernateRegistry registry = registryBySmartEntity.get(entityClass);
+ if (registry != null) {
+ EntityRepresentationStrategy myCustomStrategy;
+ myCustomStrategy = new K2EntityInstantiatorPojoStandard(
+ defaultStrategy, registry, entityClass);
+ strategyByEntity.put(entityClass, myCustomStrategy);
+ return myCustomStrategy;
+ }
+
+ return defaultStrategy;
+ }
+
+ @Override
+ public EmbeddableRepresentationStrategy resolveStrategy(
+ final Component component, final Supplier supplier,
+ final RuntimeModelCreationContext runtimeModelCreationContext) {
+
+ EmbeddableRepresentationStrategy defaultStrategy
+ = hibernateTypeResolver.resolveStrategy(component, supplier,
+ runtimeModelCreationContext);
+
+ Class> componentClass = component.getComponentClass();
+ EmbeddableRepresentationStrategy strategy =
+ strategyByComponent.get(componentClass);
+ if (strategy != null) {
+ return strategy;
+ }
+
+ HibernateRegistry registry = registryBySmartEntity.get(componentClass);
+ if (registry != null) {
+ EmbeddableRepresentationStrategy myCustomStrategy;
+ myCustomStrategy =
+ new K2EmbeddableInstantiatorPojoStandard(defaultStrategy,
+ registry, componentClass);
+ strategyByComponent.put(componentClass, myCustomStrategy);
+ return myCustomStrategy;
+ }
+
+ return defaultStrategy;
+ }
+}
diff --git a/k2-hibernate/src/main/java/com/k2/hibernate/Prefix.java b/k2-hibernate/src/main/java/com/k2/hibernate/Prefix.java
new file mode 100644
index 0000000..e2f0bca
--- /dev/null
+++ b/k2-hibernate/src/main/java/com/k2/hibernate/Prefix.java
@@ -0,0 +1,50 @@
+/* vim: set et ts=2 sw=2 cindent fo=qroca: */
+
+package com.k2.hibernate;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+/** Customizes the embedded column name prefix when using
+ * K2DbImplicitNamingStrategyComponentPath.
+ *
+ * When applied to @Embedded attributes of @Entity classes, this annotation
+ * customizes the column name prefix of the corresponding embeddable
+ * attributes.
+ *
+ * For example, assume you have an @Entity with an embeddable attribute value1,
+ * that has another attribute named value2. By default, or when using
+ * @Prefix(value = "", skip = false), the
+ * K2DbImplicitNamingStrategyComponentPath will create a column named
+ * "value_1_value_2". When using @Prefix(skip = true), the same column will be
+ * named "value_2" (without the value_1_ prefix). When using @Prefix("new"),
+ * the column will be named "new_value_2".
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Prefix {
+
+ /** The prefix to add the database column name, without the trailing _.
+ *
+ * This defaults to the empty string, meaning that it will use the default
+ * prefix as determined by K2DbImplicitNamingStrategyComponentPath.
+ *
+ * @return a prefix string, "" to use the default.
+ */
+ String value() default "";
+
+ /** Whether to skip the prefix.
+ *
+ * This defaults to false, meaning that it will use the default prefix as
+ * determined by K2DbImplicitNamingStrategyComponentPath.
+ *
+ * When setting skip to true, value must be the empty string.
+ *
+ * @return true to skip the prefix, false to use a prefix.
+ */
+ boolean skip() default false;
+}
diff --git a/k2-hibernate/src/main/java/com/k2/hibernate/SchemaGenerator.java b/k2-hibernate/src/main/java/com/k2/hibernate/SchemaGenerator.java
deleted file mode 100644
index 67f2c64..0000000
--- a/k2-hibernate/src/main/java/com/k2/hibernate/SchemaGenerator.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/* vim: set et ts=2 sw=2 cindent fo=qroca: */
-
-package com.k2.hibernate;
-
-import java.util.EnumSet;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.io.IOException;
-
-import org.apache.commons.lang3.Validate;
-
-import org.hibernate.boot.Metadata;
-
-import org.hibernate.tool.hbm2ddl.SchemaExport;
-import org.hibernate.tool.schema.TargetType;
-
-/** The hibernate schema generator.
- *
- * Class to create the ddl from the hibernate module configuration.
- */
-public class SchemaGenerator {
-
- /** The hibernate metadata, properly configured.
- *
- * It cannot be null.
- */
- private Metadata metadata;
-
- /** SchemaGenerator constructor.
- *
- * @param theMetadata the properly initialized hibernate metadata. It cannot
- * be null.
- */
- public SchemaGenerator(final Metadata theMetadata) {
- Validate.notNull(theMetadata, "The metadata cannot be null.");
- metadata = theMetadata;
- }
-
- /** Generates the database schema from hibernate metadata.
- *
- * Creates the ddl in the target/schema.ddl directory.
- */
- public void generate() {
- generate("target/schema.ddl");
- }
-
- /** Generates the database schema from hibernate metadata.
- *
- * @param ddlFile the name of the file where the generator will create
- * with the database schema. It cannot be null.
- */
- public void generate(final String ddlFile) {
- Validate.notNull(ddlFile, "The file name cannot be null.");
- try {
- Files.deleteIfExists(Paths.get(ddlFile));
- } catch (IOException e) {
- throw new RuntimeException("Error deleting " + ddlFile, e);
- }
- SchemaExport schemaExport = new SchemaExport();
- schemaExport.setFormat(true);
- schemaExport.setDelimiter(";");
- schemaExport.setOutputFile(ddlFile);
- schemaExport.execute(EnumSet.of(TargetType.SCRIPT),
- SchemaExport.Action.CREATE, metadata);
- }
-}
-
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/Address.java b/k2-hibernate/src/test/java/com/k2/hibernate/Address.java
new file mode 100644
index 0000000..5f6352a
--- /dev/null
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/Address.java
@@ -0,0 +1,44 @@
+package com.k2.hibernate;
+
+import jakarta.persistence.AttributeConverter;
+
+public class Address {
+
+ private String street;
+ private String number;
+
+ public Address(final String theStreet, final String theNumber) {
+ street = theStreet;
+ number = theNumber;
+ }
+
+ public String getStreet() {
+ return street;
+ }
+
+ public String getNumber() {
+ return number;
+ }
+
+ public static class Converter implements AttributeConverter {
+
+ @Override
+ public String convertToDatabaseColumn(final Address attribute) {
+ if (attribute != null) {
+ return attribute.getStreet() + "-" + attribute.getNumber();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public Address convertToEntityAttribute(final String value) {
+ if (value != null) {
+ String[] parts = value.split("-", 2);
+ return new Address(parts[0], parts[1]);
+ } else {
+ return null;
+ }
+ }
+ }
+}
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/Entity1.java b/k2-hibernate/src/test/java/com/k2/hibernate/Entity1.java
index fcdcaed..0975d06 100644
--- a/k2-hibernate/src/test/java/com/k2/hibernate/Entity1.java
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/Entity1.java
@@ -2,24 +2,30 @@
package com.k2.hibernate;
+import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
-import javax.persistence.Entity;
-import javax.persistence.FetchType;
-import javax.persistence.GeneratedValue;
-import javax.persistence.AttributeOverride;
-import javax.persistence.AttributeOverrides;
-import javax.persistence.Column;
-import javax.persistence.ElementCollection;
-import javax.persistence.Embedded;
-import javax.persistence.Id;
-import javax.persistence.JoinColumn;
-import javax.persistence.ManyToMany;
-import javax.persistence.OneToMany;
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.ForeignKey;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.ElementCollection;
+import jakarta.persistence.Embedded;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToMany;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.OneToMany;
+import jakarta.persistence.Table;
+import jakarta.persistence.UniqueConstraint;
/** Sample entity to use in HibernateTest. */
@Entity
+@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {
+ "this_is_a_long_attribute_name",
+ "value"})})
public class Entity1 {
/** The pk. */
@@ -28,6 +34,9 @@ public class Entity1 {
/** a sample column. */
private String value;
+ /** a sample with a very long name to test unique index key length. */
+ private String thisIsALongAttributeName;
+
/** A sample element collection, to check generated fk names. */
@ElementCollection
private List longs = null;
@@ -39,14 +48,19 @@ public class Entity1 {
/** An embedded element to test component tuplizers. */
@Embedded
- @AttributeOverrides({
- @AttributeOverride(name = "value", column = @Column(name = "value1_value"))
- })
- private Value1 value1 = null;
+ private Value1 attribute1 = null;
/** A sample entity collection, to check generated fk names. */
+ @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
+ private List manyEntities = new ArrayList<>();
+
+ /** A sample entity collection, to check generated fk with long names. */
@ManyToMany
- private List entities = null;
+ private List thisIsAVeryLongAttributeNameToForceALongFkName = null;
+
+ @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
+ @JoinColumn(foreignKey = @ForeignKey(name="fk_entity_1_one"))
+ private Entity2 oneEntity = null;
/** A sample entity collection of a class hierarchy. */
@OneToMany
@@ -81,8 +95,8 @@ public void addValue2(final Value2 someValue) {
*
* @param aValue the value 1
*/
- public void setValue1(final Value1 aValue) {
- value1 = aValue;
+ public void setAttribute1(final Value1 aValue) {
+ attribute1 = aValue;
}
/** Obtains the list of values.
@@ -97,8 +111,32 @@ public List getValue2List() {
*
* @return the value1 or null.
*/
- public Value1 getValue1() {
- return value1;
+ public Value1 getAttribute1() {
+ return attribute1;
+ }
+
+ /** Adds an Entity to the list of entities.
+ *
+ * @param entity to be added. Cannot be null.
+ */
+ public void addToManyEntities(final Entity2 entity) {
+ manyEntities.add(entity);
+ }
+
+ /** Gets the entities lazily hold by this entity.
+ *
+ * @return a list, never null.
+ */
+ public List getManyEntities() {
+ return manyEntities;
+ }
+
+ public void setOneEntity(final Entity2 theOneEntity) {
+ oneEntity = theOneEntity;
+ }
+
+ public Entity2 getOneEntity() {
+ return oneEntity;
}
/** Empty constructor. */
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/Entity2.java b/k2-hibernate/src/test/java/com/k2/hibernate/Entity2.java
index 9724cd8..f1a6080 100644
--- a/k2-hibernate/src/test/java/com/k2/hibernate/Entity2.java
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/Entity2.java
@@ -2,10 +2,10 @@
package com.k2.hibernate;
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.Id;
-import javax.persistence.Transient;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.Id;
+import jakarta.persistence.Transient;
import com.k2.hibernate.HibernateTest.StringHolder;
@@ -22,6 +22,12 @@ public class Entity2 {
/** a sample column. */
private String value;
+ /** An attribute integrated through an AttributeConverter */
+ private Address address;
+
+ /** An attribute integrated through an AttributeConverter */
+ private Phone phone;
+
/** The pk.
*
* @return the pk.
@@ -46,6 +52,22 @@ public StringHolder getParameter() {
return parameter;
}
+ /** The address.
+ *
+ * @return the address.
+ */
+ public Address getAddress() {
+ return address;
+ }
+
+ /** The phone.
+ *
+ * @return the phone.
+ */
+ public Phone getPhone() {
+ return phone;
+ }
+
/** Empty constructor with transients only.
*
* @param param a transient.
@@ -55,6 +77,8 @@ public StringHolder getParameter() {
}
/** Constructor to initialize the value.
+ *
+ * Initializes the address to Corrientes 2122 and the phone to 11-555-5555.
*
* @param param a transient.
*
@@ -63,5 +87,13 @@ public StringHolder getParameter() {
Entity2(final StringHolder param, final String theValue) {
parameter = param;
value = theValue;
+
+ address = new Address("Corrientes", "2122");
+ phone = new Phone("11", "555-5555");
+ }
+
+ /** Default constructor, required by hibernate when lazy-loading entities.
+ */
+ Entity2() {
}
}
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/Entity3.java b/k2-hibernate/src/test/java/com/k2/hibernate/Entity3.java
index c51fc2d..c947df2 100644
--- a/k2-hibernate/src/test/java/com/k2/hibernate/Entity3.java
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/Entity3.java
@@ -2,15 +2,15 @@
package com.k2.hibernate;
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.Id;
-import javax.persistence.Index;
-import javax.persistence.JoinColumn;
-import javax.persistence.ManyToOne;
-import javax.persistence.Table;
-import javax.persistence.UniqueConstraint;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.Id;
+import jakarta.persistence.Index;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
+import jakarta.persistence.UniqueConstraint;
/** Sample entity to use in HibernateTest. */
@Entity
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/Entity4.java b/k2-hibernate/src/test/java/com/k2/hibernate/Entity4.java
new file mode 100644
index 0000000..3a26cd0
--- /dev/null
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/Entity4.java
@@ -0,0 +1,59 @@
+/* vim: set et ts=2 sw=2 cindent fo=qroca: */
+
+package com.k2.hibernate;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.Embedded;
+import jakarta.persistence.Id;
+
+/** Sample entity to use in HibernateTest. */
+@Entity
+public class Entity4 {
+
+ /** The pk. */
+ private @Id @GeneratedValue long id;
+
+ /** An embedded element to test @Prefix with an empty prefix. */
+ @Embedded
+ @Prefix(skip = true)
+ private Value1 value1 = null;
+
+ /** An embedded element to test @Prefix with a specific prefix. */
+ @Embedded
+ @Prefix("prefix")
+ private Value1 attribute2 = null;
+
+ /** An embedded element to test @Prefix with default values. */
+ @Embedded
+ @Prefix
+ private Value1 attribute3 = null;
+
+ /** The pk.
+ *
+ * @return the pk.
+ */
+ public long getId() {
+ return id;
+ }
+
+ /** Sets value1.
+ *
+ * @param aValue the value 1
+ */
+ public void setValue1(final Value1 aValue) {
+ value1 = aValue;
+ }
+
+ /** Gets the value1.
+ *
+ * @return the value1 or null.
+ */
+ public Value1 getValue1() {
+ return value1;
+ }
+
+ /** Empty constructor. */
+ Entity4() {
+ }
+}
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/HibernateTest.java b/k2-hibernate/src/test/java/com/k2/hibernate/HibernateTest.java
index e10e280..05a5960 100644
--- a/k2-hibernate/src/test/java/com/k2/hibernate/HibernateTest.java
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/HibernateTest.java
@@ -4,10 +4,6 @@
import java.util.LinkedList;
import java.util.List;
-import java.util.Scanner;
-
-import java.io.File;
-import java.io.FileNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -22,6 +18,7 @@
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;
@@ -31,10 +28,9 @@
import com.k2.core.Public;
import com.k2.core.Registrator;
-import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
-import org.hibernate.criterion.Order;
+import org.springframework.transaction.support.TransactionTemplate;
public class HibernateTest {
@@ -46,7 +42,9 @@ public class HibernateTest {
@Before public void setUp() {
log.trace("Entering setUp");
application = new TestApplication();
- application.run(new String[] {"--server.port=0"});
+ application.run(new String[] {"--server.port=0",
+ "--hibernate.k2.namingStrategy"
+ + "=com.k2.hibernate.K2DbImplicitNamingStrategyComponentPath"});
log.trace("Leaving setUp");
}
@@ -103,6 +101,26 @@ public class HibernateTest {
assertThat(result.get(1).getValue(), is("second value"));
}
+ @Test public void save_withConverter() {
+ EntityRepository repo = application.getBean(
+ "testmodule.entity1Repository", EntityRepository.class);
+
+ Entity2Factory factory = application.getBean(Module1.class,
+ "entity2Factory", Entity2Factory.class);
+
+ repo.save(factory.create("first value"));
+ List result = repo.listEntity2();
+
+ // Phone and Address are custom data types with a converter.
+ assertThat(result.size(), is(1));
+ assertThat(result.get(0).getParameter().toString(),
+ is("Entity 2 factory parameter"));
+ assertThat(result.get(0).getPhone(), is(not(nullValue())));
+ assertThat(result.get(0).getPhone().getNumber(), is("555-5555"));
+ assertThat(result.get(0).getAddress(), is(not(nullValue())));
+ assertThat(result.get(0).getAddress().getStreet(), is("Corrientes"));
+ }
+
@Test public void save_withComponentFactory() {
EntityRepository repo = application.getBean(
"testmodule.entity1Repository", EntityRepository.class);
@@ -113,77 +131,17 @@ public class HibernateTest {
Entity1 entity = new Entity1("an entity");
entity.addValue2(factory2.create("one value"));
entity.addValue2(factory2.create("another value"));
- entity.setValue1(factory1.create("a value1 instance"));
+ entity.setAttribute1(factory1.create("a value1 instance"));
repo.save(entity);
List result = repo.listEntity1();
assertThat(result.size(), is(1));
assertThat(result.get(0).getValue2List().get(0).getInjected(),
is("value 2 injected value"));
- assertThat(result.get(0).getValue1().getInjected(),
+ assertThat(result.get(0).getAttribute1().getInjected(),
is("value 1 injected value"));
}
- @Test public void generateSchema() {
- SchemaGenerator schema = application.getBean(Hibernate.class, "schema",
- SchemaGenerator.class);
- schema.generate();
-
- String content = "";
- try (Scanner scanner = new Scanner(new File("target/schema.ddl"))) {
- content = scanner.useDelimiter("\\A").next();
- } catch (FileNotFoundException e) {
- throw new RuntimeException("target/schema.ddl not found", e);
- }
-
- assertThat(content, containsString("create table tm_entity_1"));
- assertThat(content, containsString("tm_uk_entity_3_unique_value"));
- assertThat(content, containsString("create index idx_entity_1_id"));
-
- // A ManyToOne joined by column.
- assertThat(content, containsString("tm_fk_entity_3_entity_1_id"));
-
- // An element collection with a long.
- assertThat(content, containsString("create table tm_entity_1_longs"));
- assertThat(content, containsString("tm_fk_entity_1_longs_entity_1_id"));
-
- // An element collection with an embeddable.
- assertThat(content, containsString(
- "create table tm_entity_1_value_2_list"));
- assertThat(content, containsString(
- "tm_fk_entity_1_value_2_list_entity_1_id"));
-
- // A many to many relation table.
- assertThat(content, containsString("create table tm_entity_1_entities"));
- assertThat(content, containsString("tm_fk_entity_1_entities_entities_id"));
-
- // A single table per class hierarchy table name.
- assertThat(content, containsString(
- "create table tm_single_table_base_class"));
-
- // All mapped super class hierarchy table names.
- assertThat(content, containsString(
- "create table tm_mapped_super_sub_class_1"));
- assertThat(content, containsString(
- "create table tm2_mapped_super_sub_class_2"));
-
- // All joined inheritance table names.
- assertThat(content, containsString("create table tm_joined_base_class"));
- assertThat(content, containsString("create table tm_joined_sub_class_1"));
- assertThat(content, containsString("create table tm2_joined_sub_class_2"));
-
- // All table per class table names.
- assertThat(content, containsString(
- "create table tm_table_per_class_base_class"));
- assertThat(content, containsString(
- "create table tm_table_per_class_sub_class_1"));
- assertThat(content, containsString(
- "create table tm2_table_per_class_sub_class_2"));
-
- // Just in case, the tm_tm_ prefix should never appear.
- assertThat(content, not(containsString("tm_tm_")));
- }
-
// Sample class to create beans in the test application.
public static class StringHolder {
private String value;
@@ -197,6 +155,43 @@ public String toString() {
}
}
+ @Test
+ public void load_withFactoryAndLazyInit() {
+ EntityRepository repo = application.getBean(
+ "testmodule.entity1Repository", EntityRepository.class);
+
+ TransactionTemplate transactionTemplate = application.getBean(
+ "testmodule.transactionTemplate", TransactionTemplate.class);
+
+ Entity2Factory factory = application.getBean(Module1.class,
+ "entity2Factory", Entity2Factory.class);
+
+ Entity1 entity1 = new Entity1("first value");
+ entity1.setOneEntity(factory.create("one entity"));
+ entity1.addToManyEntities(factory.create("another entity"));
+ repo.save(entity1);
+
+ transactionTemplate.execute((tx) -> {
+ List result = repo.listEntity1();
+
+ assertThat(result.size(), is(1));
+ Entity1 fetchedEntity1 = result.get(0);
+
+ assertThat(fetchedEntity1.getOneEntity().getValue(), is("one entity"));
+ assertThat(fetchedEntity1.getOneEntity().getParameter().toString(),
+ is("Entity 2 factory parameter"));
+
+ List manyEntities = fetchedEntity1.getManyEntities();
+ assertThat(manyEntities.size(), is(1));
+ assertThat(manyEntities.get(0).getParameter().toString(),
+ is("Entity 2 factory parameter"));
+ assertThat(manyEntities.get(0).getValue(),
+ is("another entity"));
+
+ return null;
+ });
+ }
+
/////////////////////////////////////////////////////////////////////
/////////// The module 1 declaration ///////////////////////////
/////////////////////////////////////////////////////////////////////
@@ -213,6 +208,7 @@ public void addRegistrations(final ModuleContext moduleContext) {
hibernateRegistry.registerPersistentClass(Entity2.class,
Entity2Factory.class);
hibernateRegistry.registerPersistentClass(Entity3.class);
+ hibernateRegistry.registerPersistentClass(Entity4.class);
hibernateRegistry.registerPersistentClass(Value1.class,
Value1Factory.class);
hibernateRegistry.registerPersistentClass(Value2.class,
@@ -237,6 +233,9 @@ public void addRegistrations(final ModuleContext moduleContext) {
// inheritance.
hibernateRegistry.registerPersistentClass(TablePerClassBaseClass.class);
hibernateRegistry.registerPersistentClass(TablePerClassSubClass1.class);
+
+ hibernateRegistry.registerConverter(Phone.Converter.class);
+ hibernateRegistry.registerConverter(Address.Converter.class);
}
@Bean @Public public EntityRepository entity1Repository(
@@ -244,6 +243,11 @@ public void addRegistrations(final ModuleContext moduleContext) {
return new EntityRepository(sessionFactory);
}
+ @Bean @Public public TransactionTemplate transactionTemplate(
+ final PlatformTransactionManager platformTransactionManager) {
+ return new TransactionTemplate(platformTransactionManager);
+ }
+
@Bean(name = "parameter") public StringHolder parameter() {
return new StringHolder("Entity 2 factory parameter");
}
@@ -272,9 +276,10 @@ public static class Entity2Factory {
parameter = param;
}
- Entity2 create() {
+ public Entity2 create() {
return new Entity2(parameter);
}
+
Entity2 create(final String value) {
return new Entity2(parameter, value);
}
@@ -331,18 +336,15 @@ public void save(final Entity2 instance) {
@SuppressWarnings({ "unchecked", "deprecation" })
public List listEntity1() {
Session session = sessionFactory.getCurrentSession();
- return session.createCriteria(Entity1.class)
- .addOrder(Order.asc("id"))
- .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
- .list();
+ return session.createQuery(
+ "select distinct e from com.k2.hibernate.Entity1 e order by id").list();
}
@SuppressWarnings({ "unchecked", "deprecation" })
public List listEntity2() {
Session session = sessionFactory.getCurrentSession();
- return session.createCriteria("com.k2.hibernate.Entity2")
- .addOrder(Order.asc("id"))
- .list();
+ return session.createQuery(
+ "select distinct e from com.k2.hibernate.Entity2 e order by id").list();
}
};
@@ -360,7 +362,7 @@ public void addRegistrations(final ModuleContext moduleContext) {
hibernateRegistry = moduleContext.get(HibernateRegistry.class);
// These classes test the naming convention when different classe in the
- // same hierachy belong to different modules.
+ // same hierarchy belong to different modules.
hibernateRegistry.registerPersistentClass(SingleTableSubClass2.class);
hibernateRegistry.registerPersistentClass(MappedSuperSubClass2.class);
hibernateRegistry.registerPersistentClass(JoinedSubClass2.class);
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/JoinedBaseClass.java b/k2-hibernate/src/test/java/com/k2/hibernate/JoinedBaseClass.java
index aa60e61..3cc7131 100644
--- a/k2-hibernate/src/test/java/com/k2/hibernate/JoinedBaseClass.java
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/JoinedBaseClass.java
@@ -2,12 +2,12 @@
package com.k2.hibernate;
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.Id;
-import javax.persistence.Inheritance;
-import javax.persistence.InheritanceType;
-import javax.persistence.DiscriminatorColumn;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.Id;
+import jakarta.persistence.Inheritance;
+import jakarta.persistence.InheritanceType;
+import jakarta.persistence.DiscriminatorColumn;
/** Sample entity to use in HibernateTest.
*
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/JoinedSubClass1.java b/k2-hibernate/src/test/java/com/k2/hibernate/JoinedSubClass1.java
index a109df5..e84c343 100644
--- a/k2-hibernate/src/test/java/com/k2/hibernate/JoinedSubClass1.java
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/JoinedSubClass1.java
@@ -2,7 +2,7 @@
package com.k2.hibernate;
-import javax.persistence.Entity;
+import jakarta.persistence.Entity;
/** Sample entity to use in HibernateTest. */
@Entity
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/JoinedSubClass2.java b/k2-hibernate/src/test/java/com/k2/hibernate/JoinedSubClass2.java
index 075a277..b0969cb 100644
--- a/k2-hibernate/src/test/java/com/k2/hibernate/JoinedSubClass2.java
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/JoinedSubClass2.java
@@ -2,7 +2,7 @@
package com.k2.hibernate;
-import javax.persistence.Entity;
+import jakarta.persistence.Entity;
/** Sample entity to use in HibernateTest. */
@Entity
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/MappedSuperBaseClass.java b/k2-hibernate/src/test/java/com/k2/hibernate/MappedSuperBaseClass.java
index 4276e8c..cf68bba 100644
--- a/k2-hibernate/src/test/java/com/k2/hibernate/MappedSuperBaseClass.java
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/MappedSuperBaseClass.java
@@ -2,9 +2,9 @@
package com.k2.hibernate;
-import javax.persistence.GeneratedValue;
-import javax.persistence.Id;
-import javax.persistence.MappedSuperclass;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.Id;
+import jakarta.persistence.MappedSuperclass;
/** Sample entity to use in HibernateTest.
*
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/MappedSuperSubClass1.java b/k2-hibernate/src/test/java/com/k2/hibernate/MappedSuperSubClass1.java
index e44eda7..283b7d0 100644
--- a/k2-hibernate/src/test/java/com/k2/hibernate/MappedSuperSubClass1.java
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/MappedSuperSubClass1.java
@@ -2,7 +2,7 @@
package com.k2.hibernate;
-import javax.persistence.Entity;
+import jakarta.persistence.Entity;
/** Sample entity to use in HibernateTest. */
@Entity
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/MappedSuperSubClass2.java b/k2-hibernate/src/test/java/com/k2/hibernate/MappedSuperSubClass2.java
index ab3e734..08903dd 100644
--- a/k2-hibernate/src/test/java/com/k2/hibernate/MappedSuperSubClass2.java
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/MappedSuperSubClass2.java
@@ -2,7 +2,7 @@
package com.k2.hibernate;
-import javax.persistence.Entity;
+import jakarta.persistence.Entity;
/** Sample entity to use in HibernateTest. */
@Entity
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/Phone.java b/k2-hibernate/src/test/java/com/k2/hibernate/Phone.java
new file mode 100644
index 0000000..72e20d8
--- /dev/null
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/Phone.java
@@ -0,0 +1,44 @@
+package com.k2.hibernate;
+
+import jakarta.persistence.AttributeConverter;
+
+public class Phone {
+
+ private String countryCode;
+ private String number;
+
+ public Phone(final String theCountryCode, final String theNumber) {
+ countryCode = theCountryCode;
+ number = theNumber;
+ }
+
+ public String getCountryCode() {
+ return countryCode;
+ }
+
+ public String getNumber() {
+ return number;
+ }
+
+ public static class Converter implements AttributeConverter {
+
+ @Override
+ public String convertToDatabaseColumn(final Phone attribute) {
+ if (attribute != null) {
+ return attribute.getCountryCode() + "-" + attribute.getNumber();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public Phone convertToEntityAttribute(final String value) {
+ if (value != null) {
+ String[] parts = value.split("-", 2);
+ return new Phone(parts[0], parts[1]);
+ } else {
+ return null;
+ }
+ }
+ }
+}
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/SingleTableBaseClass.java b/k2-hibernate/src/test/java/com/k2/hibernate/SingleTableBaseClass.java
index 3cd8103..facaae5 100644
--- a/k2-hibernate/src/test/java/com/k2/hibernate/SingleTableBaseClass.java
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/SingleTableBaseClass.java
@@ -2,12 +2,12 @@
package com.k2.hibernate;
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.Id;
-import javax.persistence.Inheritance;
-import javax.persistence.InheritanceType;
-import javax.persistence.DiscriminatorColumn;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.Id;
+import jakarta.persistence.Inheritance;
+import jakarta.persistence.InheritanceType;
+import jakarta.persistence.DiscriminatorColumn;
/** Sample entity to use in HibernateTest.
*
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/SingleTableSubClass1.java b/k2-hibernate/src/test/java/com/k2/hibernate/SingleTableSubClass1.java
index f1623a6..9f32846 100644
--- a/k2-hibernate/src/test/java/com/k2/hibernate/SingleTableSubClass1.java
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/SingleTableSubClass1.java
@@ -2,7 +2,7 @@
package com.k2.hibernate;
-import javax.persistence.Entity;
+import jakarta.persistence.Entity;
/** Sample entity to use in HibernateTest. */
@Entity
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/SingleTableSubClass2.java b/k2-hibernate/src/test/java/com/k2/hibernate/SingleTableSubClass2.java
index 4b83a96..d9391af 100644
--- a/k2-hibernate/src/test/java/com/k2/hibernate/SingleTableSubClass2.java
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/SingleTableSubClass2.java
@@ -2,7 +2,7 @@
package com.k2.hibernate;
-import javax.persistence.Entity;
+import jakarta.persistence.Entity;
/** Sample entity to use in HibernateTest. */
@Entity
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/TablePerClassBaseClass.java b/k2-hibernate/src/test/java/com/k2/hibernate/TablePerClassBaseClass.java
index 7fd6d1c..da1dd38 100644
--- a/k2-hibernate/src/test/java/com/k2/hibernate/TablePerClassBaseClass.java
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/TablePerClassBaseClass.java
@@ -2,12 +2,12 @@
package com.k2.hibernate;
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.Id;
-import javax.persistence.Inheritance;
-import javax.persistence.InheritanceType;
-import javax.persistence.DiscriminatorColumn;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.Id;
+import jakarta.persistence.Inheritance;
+import jakarta.persistence.InheritanceType;
+import jakarta.persistence.DiscriminatorColumn;
/** Sample entity to use in HibernateTest.
*
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/TablePerClassSubClass1.java b/k2-hibernate/src/test/java/com/k2/hibernate/TablePerClassSubClass1.java
index 0f30f72..dda35ac 100644
--- a/k2-hibernate/src/test/java/com/k2/hibernate/TablePerClassSubClass1.java
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/TablePerClassSubClass1.java
@@ -2,7 +2,7 @@
package com.k2.hibernate;
-import javax.persistence.Entity;
+import jakarta.persistence.Entity;
/** Sample entity to use in HibernateTest. */
@Entity
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/TablePerClassSubClass2.java b/k2-hibernate/src/test/java/com/k2/hibernate/TablePerClassSubClass2.java
index 3c3fab5..e11de47 100644
--- a/k2-hibernate/src/test/java/com/k2/hibernate/TablePerClassSubClass2.java
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/TablePerClassSubClass2.java
@@ -2,7 +2,7 @@
package com.k2.hibernate;
-import javax.persistence.Entity;
+import jakarta.persistence.Entity;
/** Sample entity to use in HibernateTest. */
@Entity
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/Value1.java b/k2-hibernate/src/test/java/com/k2/hibernate/Value1.java
index a9d3b6f..a6810bb 100644
--- a/k2-hibernate/src/test/java/com/k2/hibernate/Value1.java
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/Value1.java
@@ -2,9 +2,9 @@
package com.k2.hibernate;
-import javax.persistence.Embeddable;
-import javax.persistence.Embedded;
-import javax.persistence.Transient;
+import jakarta.persistence.Embeddable;
+import jakarta.persistence.Embedded;
+import jakarta.persistence.Transient;
/** Sample value object to use in HibernateTest. */
@Embeddable
@@ -18,7 +18,7 @@ public class Value1 {
/** A sample nested embeddable. */
@Embedded
- private Value2 value2;
+ private Value2 attribute2;
/** The value.
*
@@ -54,5 +54,8 @@ public String getInjected() {
injected = theInjected;
value = theValue;
}
+
+ public Value1() {
+ }
}
diff --git a/k2-hibernate/src/test/java/com/k2/hibernate/Value2.java b/k2-hibernate/src/test/java/com/k2/hibernate/Value2.java
index c3f4b6e..c0cdfdb 100644
--- a/k2-hibernate/src/test/java/com/k2/hibernate/Value2.java
+++ b/k2-hibernate/src/test/java/com/k2/hibernate/Value2.java
@@ -2,10 +2,8 @@
package com.k2.hibernate;
-import javax.persistence.Column;
-
-import javax.persistence.Embeddable;
-import javax.persistence.Transient;
+import jakarta.persistence.Embeddable;
+import jakarta.persistence.Transient;
/** Sample value object to use in HibernateTest. */
@Embeddable
@@ -15,7 +13,6 @@ public class Value2 {
@Transient private String injected;
/** a sample column. */
- @Column(name = "value_2")
private String value;
/** The value.
@@ -52,5 +49,8 @@ public String getInjected() {
injected = theInjected;
value = theValue;
}
+
+ public Value2() {
+ }
}
diff --git a/k2-hibernate/src/test/resources/com/k2/hibernate/hibernate.properties b/k2-hibernate/src/test/resources/com/k2/hibernate/hibernate.properties
index 41fb039..fd499da 100644
--- a/k2-hibernate/src/test/resources/com/k2/hibernate/hibernate.properties
+++ b/k2-hibernate/src/test/resources/com/k2/hibernate/hibernate.properties
@@ -1,6 +1,6 @@
# The hibernate dialect name
-hibernate.dialect=H2
+hibernate.dialect=org.hibernate.dialect.HSQLDialect
# Automatically validates or exports the schema to the database. NEVER USE
# ANYTHING BUT validate IN PRODUCTION!!!!
@@ -15,11 +15,11 @@ hibernate.hbm2ddl.auto=create
# Sets the connection information.
## datasource.url=jdbc:mysql://localhost:3306/database
-datasource.url=jdbc:h2:mem:db
-## datasource.driverClassName=com.mysql.jdbc.Driver
+# in memory db with mysql compatibility mode on.
+datasource.driverClassName=org.hsqldb.jdbc.JDBCDriver
+datasource.url=jdbc:hsqldb:mem:test;sql.syntax_mys=true
## datasource.username=root
-## datasource.password=pass
# Set the number of connections that will be established when the connection
# pool is started. Default value is 10. If this value exceeds
@@ -78,4 +78,3 @@ datasource.url=jdbc:h2:mem:db
# returning them to the caller or If specified, this query does not
# have to return any data, it just can't throw a SQLException.
## datasource.validationQuery = SELECT 1
-
diff --git a/k2-maven-plugin/pom.xml b/k2-maven-plugin/pom.xml
index 3db1c9c..231c48f 100644
--- a/k2-maven-plugin/pom.xml
+++ b/k2-maven-plugin/pom.xml
@@ -9,7 +9,7 @@
com.github.katari
k2-parent
- 0.1.9-SNAPSHOT
+ 0.1.13-SNAPSHOT
../k2-parent/pom.xml
diff --git a/k2-parent/pom.xml b/k2-parent/pom.xml
index 544fbbf..37014b6 100644
--- a/k2-parent/pom.xml
+++ b/k2-parent/pom.xml
@@ -9,7 +9,7 @@
com.github.katari
k2
- 0.1.9-SNAPSHOT
+ 0.1.13-SNAPSHOT
../pom.xml
@@ -21,7 +21,7 @@
org.jacoco
org.jacoco.agent
runtime
- 0.7.8
+ 0.8.10
test
@@ -53,7 +53,26 @@
ch.qos.logback
logback-classic
- 1.1.7
+ 1.4.11
+
+
+
+ jakarta.annotation
+ jakarta.annotation-api
+ 2.1.1
+
+
+
+ jakarta.xml.bind
+ jakarta.xml.bind-api
+ 4.0.0
+
+
+
+ com.sun.xml.bind
+ jaxb-impl
+ 4.0.1
+ runtime
@@ -126,9 +145,9 @@
- com.h2database
- h2
- 1.4.191
+ org.hsqldb
+ hsqldb
+ ${hsqldb.version}
test
@@ -138,13 +157,13 @@
org.eclipse.jetty
jetty-webapp
- 9.4.12.v20180830
+ 11.0.15
- javax.servlet
- javax.servlet-api
- 3.1.0
+ jakarta.servlet
+ jakarta.servlet-api
+ 6.0.0
@@ -171,40 +190,28 @@
io.swagger
swagger-annotations
- 1.5.22
+ 1.6.11
org.webjars
swagger-ui
- 3.24.3
+ 5.3.1
- javax.validation
- validation-api
- 1.1.0.Final
+ jakarta.validation
+ jakarta.validation-api
+ 3.0.2
org.hibernate
hibernate-validator
- 5.4.0.Final
-
-
-
- javax.el
- javax.el-api
- 2.2.4
-
-
-
- org.glassfish.web
- javax.el
- 2.2.4
+ 6.2.5.Final
@@ -375,34 +382,34 @@
spring-framework-bom
${spring.version}
-
+
-
-
-
- org.apache.maven
- maven-plugin-api
- 3.3.9
-
-
-
- org.apache.maven.plugin-tools
- maven-plugin-annotations
- 3.4
- provided
-
-
-
- org.apache.maven
- maven-project
- 2.2.1
-
-
-
- org.apache.maven
- maven-core
- 3.3.9
-
+
+
+
+ org.apache.maven
+ maven-plugin-api
+ 3.3.9
+
+
+
+ org.apache.maven.plugin-tools
+ maven-plugin-annotations
+ 3.4
+ provided
+
+
+
+ org.apache.maven
+ maven-project
+ 2.2.1
+
+
+
+ org.apache.maven
+ maven-core
+ 3.3.9
+
@@ -481,7 +488,10 @@
org.apache.maven.plugins
maven-javadoc-plugin
- 2.10.4
+ 3.3.2
+
+ none
+
attach-javadocs
@@ -495,7 +505,7 @@
org.jacoco
jacoco-maven-plugin
- 0.7.8
+ 0.8.10
${sonar.jacoco.reportPaths}
@@ -584,7 +594,7 @@
array -->
io.swagger.codegen.v3
swagger-codegen-maven-plugin
- 3.0.14
+ 3.0.46
@@ -592,10 +602,14 @@
- 1.7.21
- 2.0.5.RELEASE
- 5.1.8.RELEASE
- 5.4.19.Final
+ 2.0.7
+ 3.1.2
+ 6.0.11
+
+
+ 6.2.7.Final
+ 2.7.2
+
1.2.4
2.9.9
@@ -611,4 +625,3 @@
-
diff --git a/k2-shiro/pom.xml b/k2-shiro/pom.xml
index 20fef0f..ab54bbb 100644
--- a/k2-shiro/pom.xml
+++ b/k2-shiro/pom.xml
@@ -9,7 +9,7 @@
com.github.katari
k2-parent
- 0.1.9-SNAPSHOT
+ 0.1.13-SNAPSHOT
../k2-parent/pom.xml
diff --git a/k2-shiro/src/main/java/com/k2/shiro/K2SessionManager.java b/k2-shiro/src/main/java/com/k2/shiro/K2SessionManager.java
index caf94d1..a93b629 100644
--- a/k2-shiro/src/main/java/com/k2/shiro/K2SessionManager.java
+++ b/k2-shiro/src/main/java/com/k2/shiro/K2SessionManager.java
@@ -2,8 +2,8 @@
package com.k2.shiro;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.Validate;
diff --git a/k2-shiro/src/main/java/com/k2/shiro/Shiro.java b/k2-shiro/src/main/java/com/k2/shiro/Shiro.java
index fc353ba..1670343 100644
--- a/k2-shiro/src/main/java/com/k2/shiro/Shiro.java
+++ b/k2-shiro/src/main/java/com/k2/shiro/Shiro.java
@@ -5,7 +5,7 @@
import java.util.Map;
import java.util.LinkedHashMap;
-import javax.servlet.Filter;
+import jakarta.servlet.Filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -123,7 +123,7 @@ public ShiroRegistry getRegistry(final ModuleDefinition requestor) {
* @return a properly initialized shiro filter, set up to filter all
* requests. Never returns null.
*/
- @Bean public FilterRegistrationBean shiroFilter(
+ @Bean public FilterRegistrationBean shiroFilter(
final SecurityManager securityManager) {
ShiroFilterFactoryBean filterFactory = new ShiroFilterFactoryBean();
filterFactory.setSecurityManager(securityManager);
@@ -142,7 +142,8 @@ public ShiroRegistry getRegistry(final ModuleDefinition requestor) {
throw new RuntimeException("Error creating shiro filter.", e);
}
- FilterRegistrationBean registration = new FilterRegistrationBean(filter);
+ FilterRegistrationBean registration;
+ registration = new FilterRegistrationBean<>(filter);
registration.setName("shiroFilter");
registration.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
diff --git a/k2-swagger/pom.xml b/k2-swagger/pom.xml
index 4a33a26..f55ceaa 100755
--- a/k2-swagger/pom.xml
+++ b/k2-swagger/pom.xml
@@ -9,7 +9,7 @@
com.github.katari
k2-parent
- 0.1.9-SNAPSHOT
+ 0.1.13-SNAPSHOT
../k2-parent/pom.xml
@@ -63,8 +63,18 @@
- javax.servlet
- javax.servlet-api
+ jakarta.servlet
+ jakarta.servlet-api
+
+
+
+ jakarta.annotation
+ jakarta.annotation-api
+
+
+
+ jakarta.xml.bind
+ jakarta.xml.bind-api
@@ -116,8 +126,8 @@
- javax.validation
- validation-api
+ jakarta.validation
+ jakarta.validation-api
@@ -125,16 +135,6 @@
hibernate-validator
-
- javax.el
- javax.el-api
-
-
-
- org.glassfish.web
- javax.el
-
-
@@ -201,6 +201,7 @@
com.k2.swagger.api
true
java8
+ true
diff --git a/k2-swagger/src/main/java/com/k2/swagger/SwaggerController.java b/k2-swagger/src/main/java/com/k2/swagger/SwaggerController.java
index f852534..f4f80ea 100755
--- a/k2-swagger/src/main/java/com/k2/swagger/SwaggerController.java
+++ b/k2-swagger/src/main/java/com/k2/swagger/SwaggerController.java
@@ -18,7 +18,7 @@
import org.apache.commons.lang3.Validate;
-import javax.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.HttpEntity;
import org.springframework.stereotype.Controller;
diff --git a/pom.xml b/pom.xml
index 66279bc..37ece87 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
com.github.katari
k2
- 0.1.9-SNAPSHOT
+ 0.1.13-SNAPSHOT
pom
K2 project aggregator
@@ -107,6 +107,11 @@
+
+
+ 17
+ 17
+