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 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> 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 +