Merge remote-tracking branch 'upstream5/master' into wip/6.0_merged_4
This commit is contained in:
commit
4b6777cde2
|
@ -286,6 +286,9 @@ The suffix for columns storing "Modified Flags".
|
|||
+
|
||||
For example, a property called "age", will by default get modified flag with column name "age_MOD".
|
||||
|
||||
`*org.hibernate.envers.modified_column_naming_strategy*` (default: `org.hibernate.envers.boot.internal.LegacyModifiedColumnNamingStrategy` )::
|
||||
The naming strategy to be used for modified flag columns in the audit metadata.
|
||||
|
||||
`*org.hibernate.envers.embeddable_set_ordinal_field_name*` (default: `SETORDINAL` )::
|
||||
Name of column used for storing ordinal of the change in sets of embeddable elements.
|
||||
|
||||
|
@ -314,6 +317,7 @@ The following configuration options have been added recently and should be regar
|
|||
. `org.hibernate.envers.track_entities_changed_in_revision`
|
||||
. `org.hibernate.envers.using_modified_flag`
|
||||
. `org.hibernate.envers.modified_flag_suffix`
|
||||
. `org.hibernate.envers.modified_column_naming_strategy`
|
||||
. `org.hibernate.envers.original_id_prop_name`
|
||||
. `org.hibernate.envers.find_by_revision_exact_match`
|
||||
====
|
||||
|
@ -721,6 +725,77 @@ include::{extrasdir}/envers-tracking-properties-changes-example.sql[]
|
|||
|
||||
To see how "Modified Flags" can be utilized, check out the very simple query API that uses them: <<envers-tracking-properties-changes-queries>>.
|
||||
|
||||
[[envers-tracking-properties-changes-strategy]]
|
||||
=== Selecting strategy for tracking property level changes
|
||||
|
||||
By default, Envers uses the `legacy` modified column naming strategy.
|
||||
This strategy is designed to add columns based the following rule-set:
|
||||
|
||||
. If property is annotated with `@Audited` and the _modifiedColumnName_ attribute is specified, the column will directly be based on the supplied name.
|
||||
. If property is not annotated with `@Audited` or if no _modifiedColumnName_ attribute is given, the column will be named after the java class property, appended with the configured suffix, the default being `_MOD`.
|
||||
|
||||
While this strategy has no performance drawbacks, it does present concerns for users who prefer consistency without verbosity.
|
||||
Lets take the following entity mapping as an example.
|
||||
|
||||
```
|
||||
@Audited(withModifiedFlags = true)
|
||||
@Entity
|
||||
public class Customer {
|
||||
@Id
|
||||
private Integer id;
|
||||
@Column(name = "customer_name")
|
||||
private String name;
|
||||
}
|
||||
```
|
||||
|
||||
This mapping will actually lead to some inconsistent naming between columns, see below with how the model's name will be stored in `customer_name` but the modified column that tracks whether this column changes between revisions is named `name_MOD`.
|
||||
|
||||
```
|
||||
CREATE TABLE Customer_AUD (
|
||||
id bigint not null,
|
||||
REV integer not null,
|
||||
REVTYPE tinyint not null,
|
||||
customer_name varchar(255),
|
||||
name_MOD boolean,
|
||||
primary key(id, REV)
|
||||
)
|
||||
```
|
||||
|
||||
An additional strategy called `improved`, aims to address these consistent column naming concerns.
|
||||
This strategy uses the following rule-set:
|
||||
|
||||
. Property is a Basic type (Single Column valued property)
|
||||
.. Use the _modifiedColumnName_ directly if one is supplied on the property mapping
|
||||
.. Otherwise use the resolved ORM column name appended with the modified flag suffix configured value.
|
||||
. Property is an Association (to-one mapping) with a Foreign Key using a single column
|
||||
.. Use the _modifiedColumnName_ directly if one is supplied on the property mapping
|
||||
.. Otherwise use the resolved ORM column name appended with the modified flag suffix configured value.
|
||||
. Property is an Association (to-one mapping) with a Foreign Key using multiple columns
|
||||
.. Use the _modifiedColumnName_ directly if one is supplied on the property mapping
|
||||
.. Otherwise use the property name appended with the modified flag suffix configured value.
|
||||
. Property is an Embeddable
|
||||
.. Use the _modifiedColumnName_ directly if one is supplied on the property mapping
|
||||
.. Otherwise use the property name appended with the modified flag suffix configured value.
|
||||
|
||||
While using this strategy, the same `Customer` mapping will generate the following table schema:
|
||||
|
||||
```
|
||||
CREATE TABLE Customer_AUD (
|
||||
id bigint not null,
|
||||
REV integer not null,
|
||||
REVTYPE tinyint not null,
|
||||
customer_name varchar(255),
|
||||
customer_name_MOD boolean,
|
||||
primary key(id, REV)
|
||||
)
|
||||
```
|
||||
|
||||
When already using Envers in conjunction with the modified columns flag feature, its advised not to enable the new strategy immediately as schema changes would be required.
|
||||
You will need to either migrate your existing schema manually to adhere to the rules above or use the explicit _modifiedColumnName_ attribute on the `@Audited` annotation for existing columns that use the feature.
|
||||
|
||||
To configure a custom strategy implementation or use the improved strategy, the configuration option `org.hibernate.envers.modified_column_naming_strategy` will need to be set.
|
||||
This option can be the fully qualified class name of a `ModifiedColumnNameStrategy` implementation or `legacy` or `improved` for either of the two provided implementations.
|
||||
|
||||
[[envers-queries]]
|
||||
=== Queries
|
||||
|
||||
|
|
|
@ -285,21 +285,21 @@ public class DefaultLoadEventListener implements LoadEventListener {
|
|||
|
||||
LazyInitializer li = ( (HibernateProxy) proxy ).getHibernateLazyInitializer();
|
||||
|
||||
if ( li.isUnwrap() || event.getShouldUnwrapProxy() ) {
|
||||
return li.getImplementation();
|
||||
if ( li.isUnwrap() ) {
|
||||
if ( entityMetamodel.hasSubclasses() ) {
|
||||
LOG.debug( "Ignoring NO_PROXY for to-one association with subclasses to honor laziness" );
|
||||
}
|
||||
else {
|
||||
return li.getImplementation();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return persistenceContext.narrowProxy( proxy, persister, keyToLoad, null );
|
||||
}
|
||||
|
||||
// specialized handling for entities with subclasses with a HibernateProxy factory
|
||||
if ( entityMetamodel.hasSubclasses() ) {
|
||||
// entities with subclasses that define a ProxyFactory can create
|
||||
// a HibernateProxy so long as NO_PROXY was not specified.
|
||||
if ( event.getShouldUnwrapProxy() != null && event.getShouldUnwrapProxy() ) {
|
||||
LOG.debug( "Ignoring NO_PROXY for to-one association with subclasses to honor laziness" );
|
||||
}
|
||||
// entities with subclasses that define a ProxyFactory can create a HibernateProxy
|
||||
return createProxy( event, persister, keyToLoad, persistenceContext );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,8 +47,6 @@ public class LoadEvent extends AbstractEvent {
|
|||
private Object result;
|
||||
private PostLoadEvent postLoadEvent;
|
||||
|
||||
private Boolean shouldUnwrapProxy;
|
||||
|
||||
public LoadEvent(Serializable entityId, Object instanceToLoad, EventSource source) {
|
||||
this( entityId, null, instanceToLoad, DEFAULT_LOCK_OPTIONS, false, source );
|
||||
}
|
||||
|
@ -192,19 +190,4 @@ public class LoadEvent extends AbstractEvent {
|
|||
public void setPostLoadEvent(PostLoadEvent postLoadEvent) {
|
||||
this.postLoadEvent = postLoadEvent;
|
||||
}
|
||||
|
||||
public Boolean getShouldUnwrapProxy() {
|
||||
if ( shouldUnwrapProxy == null ) {
|
||||
final boolean enabled = getSession().getFactory()
|
||||
.getSessionFactoryOptions()
|
||||
.isEnhancementAsProxyEnabled();
|
||||
return enabled;
|
||||
}
|
||||
|
||||
return shouldUnwrapProxy;
|
||||
}
|
||||
|
||||
public void setShouldUnwrapProxy(Boolean shouldUnwrapProxy) {
|
||||
this.shouldUnwrapProxy = shouldUnwrapProxy;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1014,7 +1014,6 @@ public final class SessionImpl
|
|||
loadEvent = null;
|
||||
|
||||
event = recycleEventInstance( event, id, entityName );
|
||||
event.setShouldUnwrapProxy( unwrapProxy );
|
||||
|
||||
fireLoadNoChecks( event, type );
|
||||
|
||||
|
@ -1054,7 +1053,6 @@ public final class SessionImpl
|
|||
event.setLockMode( LoadEvent.DEFAULT_LOCK_MODE );
|
||||
event.setLockScope( LoadEvent.DEFAULT_LOCK_OPTIONS.getScope() );
|
||||
event.setLockTimeout( LoadEvent.DEFAULT_LOCK_OPTIONS.getTimeOut() );
|
||||
event.setShouldUnwrapProxy( null );
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.bootstrap;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.logging.Logger;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
|
||||
|
||||
import org.hibernate.testing.env.ConnectionProviderBuilder;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class DataSourceStub implements DataSource {
|
||||
private final String id;
|
||||
private final DriverManagerConnectionProviderImpl connectionProvider;
|
||||
private PrintWriter printWriter;
|
||||
|
||||
DataSourceStub(String id) {
|
||||
this.id = id;
|
||||
connectionProvider = new DriverManagerConnectionProviderImpl();
|
||||
connectionProvider.configure( ConnectionProviderBuilder.getConnectionProviderProperties() );
|
||||
|
||||
printWriter = null;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
return connectionProvider.getConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection(String username, String password) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter getLogWriter() {
|
||||
return printWriter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLogWriter(PrintWriter out) {
|
||||
this.printWriter = out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoginTimeout(int seconds) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLoginTimeout() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getParentLogger() {
|
||||
return Logger.getGlobal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> iface) {
|
||||
//noinspection unchecked
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWrapperFor(Class<?> iface) {
|
||||
return iface.isAssignableFrom( getClass() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DataSourceImpl(" + id + ")";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.bootstrap;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.spi.PersistenceProvider;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
import org.hibernate.testing.util.jpa.PersistenceUnitInfoAdapter;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class PersistenceUnitInfoTests extends BaseUnitTestCase {
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-13432" )
|
||||
@FailureExpected( jiraKey = "HHH-13432" )
|
||||
public void testJtaDataExposedAsProperty() {
|
||||
final DataSource puDataSource = new DataSourceStub( "puDataSource" );
|
||||
final PersistenceUnitInfoAdapter info = new PersistenceUnitInfoAdapter() {
|
||||
|
||||
@Override
|
||||
public DataSource getNonJtaDataSource() {
|
||||
return puDataSource;
|
||||
}
|
||||
};
|
||||
|
||||
final PersistenceProvider provider = new HibernatePersistenceProvider();
|
||||
|
||||
final EntityManagerFactory emf = provider.createContainerEntityManagerFactory(
|
||||
info,
|
||||
Collections.emptyMap()
|
||||
);
|
||||
|
||||
final Map<String, Object> properties = emf.getProperties();
|
||||
final Object o = properties.get( AvailableSettings.JPA_JTA_DATASOURCE );
|
||||
assertEquals( o, puDataSource );
|
||||
}
|
||||
}
|
|
@ -6,13 +6,9 @@
|
|||
*/
|
||||
package org.hibernate.orm.test.bootstrap;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Logger;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.spi.PersistenceProvider;
|
||||
import javax.persistence.spi.PersistenceUnitInfo;
|
||||
|
@ -100,7 +96,7 @@ public class PersistenceUnitOverridesTests extends BaseUnitTestCase {
|
|||
final Properties puProperties;
|
||||
|
||||
{
|
||||
puDataSource = new DataSourceImpl( "puDataSource" );
|
||||
puDataSource = new DataSourceStub( "puDataSource" );
|
||||
|
||||
puProperties = new Properties();
|
||||
puProperties.putAll( info.getProperties() );
|
||||
|
@ -161,7 +157,7 @@ public class PersistenceUnitOverridesTests extends BaseUnitTestCase {
|
|||
final DataSource puDataSource;
|
||||
|
||||
{
|
||||
puDataSource = new DataSourceImpl( "puDataSource" );
|
||||
puDataSource = new DataSourceStub( "puDataSource" );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -209,8 +205,8 @@ public class PersistenceUnitOverridesTests extends BaseUnitTestCase {
|
|||
"have precedence over integration settings, which is also incorrect"
|
||||
)
|
||||
public void testPassingIntegrationJpaDataSourceOverrideForJtaDataSourceElement() {
|
||||
final DataSource puDataSource = new DataSourceImpl( "puDataSource" );
|
||||
final DataSource integrationDataSource = new DataSourceImpl( "integrationDataSource" );
|
||||
final DataSource puDataSource = new DataSourceStub( "puDataSource" );
|
||||
final DataSource integrationDataSource = new DataSourceStub( "integrationDataSource" );
|
||||
|
||||
PersistenceProvider provider = new HibernatePersistenceProvider() {
|
||||
@Override
|
||||
|
@ -263,7 +259,7 @@ public class PersistenceUnitOverridesTests extends BaseUnitTestCase {
|
|||
public void testIntegrationOverridesOfPersistenceXmlDataSource() {
|
||||
|
||||
// mimics a DataSource defined in the persistence.xml
|
||||
final DataSourceImpl dataSource = new DataSourceImpl( "puDataSource" );
|
||||
final DataSourceStub dataSource = new DataSourceStub( "puDataSource" );
|
||||
final PersistenceUnitInfoAdapter info = new PersistenceUnitInfoAdapter() {
|
||||
|
||||
@Override
|
||||
|
@ -274,7 +270,7 @@ public class PersistenceUnitOverridesTests extends BaseUnitTestCase {
|
|||
|
||||
|
||||
// Now create "integration Map" that overrides the DataSource to use
|
||||
final DataSource override = new DataSourceImpl( "integrationDataSource" );
|
||||
final DataSource override = new DataSourceStub( "integrationDataSource" );
|
||||
final Map<String,Object> integrationSettings = new HashMap<>();
|
||||
integrationSettings.put( AvailableSettings.JPA_NON_JTA_DATASOURCE, override );
|
||||
|
||||
|
@ -308,7 +304,7 @@ public class PersistenceUnitOverridesTests extends BaseUnitTestCase {
|
|||
public void testIntegrationOverridesOfPersistenceXmlDataSourceWithDriverManagerInfo() {
|
||||
|
||||
// mimics a DataSource defined in the persistence.xml
|
||||
final DataSourceImpl dataSource = new DataSourceImpl( "puDataSource" );
|
||||
final DataSourceStub dataSource = new DataSourceStub( "puDataSource" );
|
||||
final PersistenceUnitInfoAdapter info = new PersistenceUnitInfoAdapter() {
|
||||
|
||||
@Override
|
||||
|
@ -335,71 +331,4 @@ public class PersistenceUnitOverridesTests extends BaseUnitTestCase {
|
|||
assertThat( connectionProvider, instanceOf( DriverManagerConnectionProviderImpl.class ) );
|
||||
}
|
||||
|
||||
private static class DataSourceImpl implements DataSource {
|
||||
private final String id;
|
||||
private final DriverManagerConnectionProviderImpl connectionProvider;
|
||||
private PrintWriter printWriter;
|
||||
|
||||
DataSourceImpl(String id) {
|
||||
this.id = id;
|
||||
connectionProvider = new DriverManagerConnectionProviderImpl();
|
||||
connectionProvider.configure( ConnectionProviderBuilder.getConnectionProviderProperties() );
|
||||
|
||||
printWriter = null;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
return connectionProvider.getConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection(String username, String password) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter getLogWriter() {
|
||||
return printWriter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLogWriter(PrintWriter out) {
|
||||
this.printWriter = out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoginTimeout(int seconds) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLoginTimeout() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getParentLogger() {
|
||||
return Logger.getGlobal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> iface) {
|
||||
//noinspection unchecked
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWrapperFor(Class<?> iface) {
|
||||
return iface.isAssignableFrom( getClass() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DataSourceImpl(" + id + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.hibernate.boot.MetadataSources;
|
|||
import org.hibernate.boot.SessionFactoryBuilder;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
|
@ -63,7 +64,6 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
|
|||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( jiraKey = "HHH-13640")
|
||||
public void testNewProxyAssociation() {
|
||||
inTransaction(
|
||||
session -> {
|
||||
|
@ -80,6 +80,7 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
|
|||
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
|
||||
assertFalse( Hibernate.isInitialized( otherEntity.animal ) );
|
||||
assertTrue( HibernateProxy.class.isInstance( otherEntity.animal ) );
|
||||
Animal animal = session.load( Animal.class, "A Human" );
|
||||
assertFalse( Hibernate.isInitialized( animal ) );
|
||||
}
|
||||
|
@ -87,8 +88,7 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
|
|||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( jiraKey = "HHH-13640")
|
||||
public void testReusedProxyAssociation() {
|
||||
public void testExistingProxyAssociation() {
|
||||
inTransaction(
|
||||
session -> {
|
||||
Human human = new Human( "A Human" );
|
||||
|
@ -105,8 +105,43 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
|
|||
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
|
||||
assertFalse( Hibernate.isInitialized( otherEntity.animal ) );
|
||||
assertTrue( HibernateProxy.class.isInstance( otherEntity.animal ) );
|
||||
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "primate" ) );
|
||||
assertFalse( Hibernate.isInitialized( otherEntity.primate ) );
|
||||
assertTrue( HibernateProxy.class.isInstance( otherEntity.primate ) );
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( jiraKey = "HHH-13640" )
|
||||
public void testExistingProxyAssociationLeafSubclass() {
|
||||
inTransaction(
|
||||
session -> {
|
||||
Human human = new Human( "A Human" );
|
||||
OtherEntity otherEntity = new OtherEntity( "test1" );
|
||||
otherEntity.animal = human;
|
||||
otherEntity.primate = human;
|
||||
otherEntity.human = human;
|
||||
session.persist( human );
|
||||
session.persist( otherEntity );
|
||||
}
|
||||
);
|
||||
|
||||
inSession(
|
||||
session -> {
|
||||
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
|
||||
assertFalse( Hibernate.isInitialized( otherEntity.animal ) );
|
||||
assertTrue( HibernateProxy.class.isInstance( otherEntity.animal ) );
|
||||
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "primate" ) );
|
||||
assertFalse( Hibernate.isInitialized( otherEntity.primate ) );
|
||||
assertTrue( HibernateProxy.class.isInstance( otherEntity.primate ) );
|
||||
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
|
||||
// TODO: Should otherEntity.human be a narrowed HibernateProxy or
|
||||
// an uninitialized non-HibernateProxy proxy?
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.envers.boot.internal;
|
||||
|
||||
import org.hibernate.envers.boot.spi.ModifiedColumnNamingStrategy;
|
||||
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
||||
import org.hibernate.envers.configuration.internal.metadata.MetadataTools;
|
||||
import org.hibernate.envers.configuration.internal.metadata.reader.PropertyAuditingData;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.ManyToOneType;
|
||||
import org.hibernate.type.OneToOneType;
|
||||
|
||||
import org.dom4j.Element;
|
||||
|
||||
/**
|
||||
* A {@link ModifiedColumnNamingStrategy} that adds modified columns with the following rules:
|
||||
* <ul>
|
||||
* <li>For basic types, prioritizes audit annotation naming followed by physical column name appended with suffix.</li>
|
||||
* <li>For associations with single column foreign keys, behaves like basic types.</li>
|
||||
* <li>For associations with multiple column foreign keys, prioritizes audit annotation naming followed by using property name.</li>
|
||||
* <li>For embeddables, behaves like associations with multiple column foreign keys</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Chris Cranford
|
||||
* @since 5.4.7
|
||||
*/
|
||||
public class ImprovedModifiedColumnNamingStrategy extends LegacyModifiedColumnNamingStrategy {
|
||||
@Override
|
||||
public void addModifiedColumns(
|
||||
GlobalConfiguration globalCfg,
|
||||
Value value,
|
||||
Element parent,
|
||||
PropertyAuditingData propertyAuditingData) {
|
||||
|
||||
boolean basicType = value.getType() instanceof BasicType;
|
||||
boolean toOneType = value.getType() instanceof ManyToOneType || value.getType() instanceof OneToOneType;
|
||||
|
||||
if ( basicType || toOneType ) {
|
||||
if ( value.getColumnSpan() == 1 ) {
|
||||
Selectable selectable = value.getColumnIterator().next();
|
||||
if ( selectable instanceof Column ) {
|
||||
// This should not be applied for formulas
|
||||
final String columnName;
|
||||
if ( !propertyAuditingData.isModifiedFlagNameExplicitlySpecified() ) {
|
||||
columnName = ( (Column) selectable ).getName() + globalCfg.getModifiedFlagSuffix();
|
||||
}
|
||||
else {
|
||||
columnName = propertyAuditingData.getExplicitModifiedFlagName();
|
||||
}
|
||||
|
||||
MetadataTools.addModifiedFlagPropertyWithColumn(
|
||||
parent,
|
||||
propertyAuditingData.getName(),
|
||||
globalCfg.getModifiedFlagSuffix(),
|
||||
propertyAuditingData.getModifiedFlagName(),
|
||||
columnName
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default legacy behavior
|
||||
super.addModifiedColumns( globalCfg, value, parent, propertyAuditingData );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.envers.boot.internal;
|
||||
|
||||
import org.hibernate.envers.boot.spi.ModifiedColumnNamingStrategy;
|
||||
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
||||
import org.hibernate.envers.configuration.internal.metadata.MetadataTools;
|
||||
import org.hibernate.envers.configuration.internal.metadata.reader.PropertyAuditingData;
|
||||
import org.hibernate.mapping.Value;
|
||||
|
||||
import org.dom4j.Element;
|
||||
|
||||
/**
|
||||
* A {@link ModifiedColumnNamingStrategy} that adds modified columns with the following rules:
|
||||
* <ul>
|
||||
* <li>If an audit annotation modified column name is supplied, use it directly with no suffix.</li>
|
||||
* <li>If no audit annotation modified column name is present, use the property name appended with suffix.</li>
|
||||
* </ul>
|
||||
*
|
||||
* This is the default Envers modified column naming behavior.
|
||||
*
|
||||
* @author Chris Cranford
|
||||
* @since 5.4.7
|
||||
*/
|
||||
public class LegacyModifiedColumnNamingStrategy implements ModifiedColumnNamingStrategy {
|
||||
@Override
|
||||
public void addModifiedColumns(
|
||||
GlobalConfiguration globalCfg,
|
||||
Value value,
|
||||
Element parent,
|
||||
PropertyAuditingData propertyAuditingData) {
|
||||
final String columnName;
|
||||
if ( propertyAuditingData.isModifiedFlagNameExplicitlySpecified() ) {
|
||||
columnName = propertyAuditingData.getExplicitModifiedFlagName();
|
||||
}
|
||||
else {
|
||||
columnName = propertyAuditingData.getModifiedFlagName();
|
||||
}
|
||||
MetadataTools.addModifiedFlagProperty(
|
||||
parent,
|
||||
propertyAuditingData.getName(),
|
||||
globalCfg.getModifiedFlagSuffix(),
|
||||
columnName
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.envers.boot.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.boot.registry.selector.SimpleStrategyRegistrationImpl;
|
||||
import org.hibernate.boot.registry.selector.StrategyRegistration;
|
||||
import org.hibernate.boot.registry.selector.StrategyRegistrationProvider;
|
||||
import org.hibernate.envers.boot.spi.ModifiedColumnNamingStrategy;
|
||||
|
||||
/**
|
||||
* A {@link StrategyRegistrationProvider} for {@link ModifiedColumnNamingStrategy}s.
|
||||
*
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
public class ModifiedColumnNamingStrategyRegistrationProvider implements StrategyRegistrationProvider {
|
||||
@Override
|
||||
public Iterable<StrategyRegistration> getStrategyRegistrations() {
|
||||
final List<StrategyRegistration> registrations = new ArrayList<>();
|
||||
|
||||
registrations.add(
|
||||
new SimpleStrategyRegistrationImpl(
|
||||
ModifiedColumnNamingStrategy.class,
|
||||
LegacyModifiedColumnNamingStrategy.class,
|
||||
"default", "legacy"
|
||||
)
|
||||
);
|
||||
|
||||
registrations.add(
|
||||
new SimpleStrategyRegistrationImpl(
|
||||
ModifiedColumnNamingStrategy.class,
|
||||
ImprovedModifiedColumnNamingStrategy.class,
|
||||
"improved"
|
||||
)
|
||||
);
|
||||
|
||||
return registrations;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.envers.boot.spi;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
||||
import org.hibernate.envers.configuration.internal.metadata.reader.PropertyAuditingData;
|
||||
import org.hibernate.mapping.Value;
|
||||
|
||||
import org.dom4j.Element;
|
||||
|
||||
/**
|
||||
* Defines a naming strategy for applying modified columns to the audited entity metamodel.
|
||||
*
|
||||
* @author Chris Cranford
|
||||
* @since 5.4.7
|
||||
*/
|
||||
@Incubating
|
||||
public interface ModifiedColumnNamingStrategy {
|
||||
/**
|
||||
* Adds modified columns to the audited entity metamodel.
|
||||
*
|
||||
* @param globalCfg the envers global configuration
|
||||
* @param value the property value
|
||||
* @param parent the parent audited entity metamodel
|
||||
* @param propertyAuditingData the property auditing data
|
||||
*/
|
||||
void addModifiedColumns(
|
||||
GlobalConfiguration globalCfg,
|
||||
Value value,
|
||||
Element parent,
|
||||
PropertyAuditingData propertyAuditingData);
|
||||
}
|
|
@ -133,4 +133,13 @@ public interface EnversSettings {
|
|||
* @since 5.4.4
|
||||
*/
|
||||
String FIND_BY_REVISION_EXACT_MATCH = "org.hibernate.envers.find_by_revision_exact_match";
|
||||
|
||||
/**
|
||||
* Specifies the {@link org.hibernate.envers.boot.spi.ModifiedColumnNamingStrategy} to use
|
||||
*
|
||||
* Defaults to {@link org.hibernate.envers.boot.internal.LegacyModifiedColumnNamingStrategy}.
|
||||
*
|
||||
* @since 5.4.7
|
||||
*/
|
||||
String MODIFIED_COLUMN_NAMING_STRATEGY = "org.hibernate.envers.modified_column_naming_strategy";
|
||||
}
|
||||
|
|
|
@ -7,13 +7,17 @@
|
|||
package org.hibernate.envers.configuration.internal;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
|
||||
import org.hibernate.boot.registry.selector.spi.StrategySelector;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.HSQLDialect;
|
||||
import org.hibernate.envers.RevisionListener;
|
||||
import org.hibernate.envers.boot.internal.EnversService;
|
||||
import org.hibernate.envers.boot.internal.LegacyModifiedColumnNamingStrategy;
|
||||
import org.hibernate.envers.boot.spi.ModifiedColumnNamingStrategy;
|
||||
import org.hibernate.envers.configuration.EnversSettings;
|
||||
import org.hibernate.envers.internal.tools.ReflectionTools;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
|
@ -77,11 +81,15 @@ public class GlobalConfiguration {
|
|||
*/
|
||||
private final String correlatedSubqueryOperator;
|
||||
|
||||
private final ModifiedColumnNamingStrategy modifiedColumnNamingStrategy;
|
||||
|
||||
public GlobalConfiguration(
|
||||
EnversService enversService,
|
||||
Map properties) {
|
||||
this.enversService = enversService;
|
||||
|
||||
final StrategySelector strategySelector = enversService.getServiceRegistry().getService( StrategySelector.class );
|
||||
|
||||
generateRevisionsForCollections = ConfigurationHelper.getBoolean(
|
||||
EnversSettings.REVISION_ON_COLLECTION_CHANGE,
|
||||
properties,
|
||||
|
@ -156,6 +164,21 @@ public class GlobalConfiguration {
|
|||
revisionListenerClass = null;
|
||||
}
|
||||
|
||||
modifiedColumnNamingStrategy = strategySelector.resolveDefaultableStrategy(
|
||||
ModifiedColumnNamingStrategy.class,
|
||||
properties.get( EnversSettings.MODIFIED_COLUMN_NAMING_STRATEGY ),
|
||||
new Callable<ModifiedColumnNamingStrategy>() {
|
||||
@Override
|
||||
public ModifiedColumnNamingStrategy call() throws Exception {
|
||||
return strategySelector.resolveDefaultableStrategy(
|
||||
ModifiedColumnNamingStrategy.class,
|
||||
"default",
|
||||
new LegacyModifiedColumnNamingStrategy()
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
allowIdentifierReuse = ConfigurationHelper.getBoolean(
|
||||
EnversSettings.ALLOW_IDENTIFIER_REUSE, properties, false
|
||||
);
|
||||
|
@ -232,4 +255,8 @@ public class GlobalConfiguration {
|
|||
public boolean isAuditReaderFindAtRevisionExactMatch() {
|
||||
return findByRevisionExactMatch;
|
||||
}
|
||||
|
||||
public ModifiedColumnNamingStrategy getModifiedColumnNamingStrategy() {
|
||||
return modifiedColumnNamingStrategy;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -213,7 +213,7 @@ public final class AuditMetadataGenerator {
|
|||
}
|
||||
return;
|
||||
}
|
||||
addModifiedFlagIfNeeded( parent, propertyAuditingData, processModifiedFlag );
|
||||
addModifiedFlagIfNeeded( value, parent, propertyAuditingData, processModifiedFlag );
|
||||
}
|
||||
|
||||
private boolean processedInSecondPass(Type type) {
|
||||
|
@ -290,19 +290,20 @@ public final class AuditMetadataGenerator {
|
|||
else {
|
||||
return;
|
||||
}
|
||||
addModifiedFlagIfNeeded( parent, propertyAuditingData, processModifiedFlag );
|
||||
addModifiedFlagIfNeeded( value, parent, propertyAuditingData, processModifiedFlag );
|
||||
}
|
||||
|
||||
private void addModifiedFlagIfNeeded(
|
||||
Value value,
|
||||
Element parent,
|
||||
PropertyAuditingData propertyAuditingData,
|
||||
boolean processModifiedFlag) {
|
||||
if ( processModifiedFlag && propertyAuditingData.isUsingModifiedFlag() ) {
|
||||
MetadataTools.addModifiedFlagProperty(
|
||||
globalCfg.getModifiedColumnNamingStrategy().addModifiedColumns(
|
||||
globalCfg,
|
||||
value,
|
||||
parent,
|
||||
propertyAuditingData.getName(),
|
||||
globalCfg.getModifiedFlagSuffix(),
|
||||
propertyAuditingData.getModifiedFlagName()
|
||||
propertyAuditingData
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,6 +95,26 @@ public final class MetadataTools {
|
|||
);
|
||||
}
|
||||
|
||||
public static Element addModifiedFlagPropertyWithColumn(
|
||||
Element parent,
|
||||
String propertyName,
|
||||
String suffix,
|
||||
String modifiedFlagName,
|
||||
String columnName) {
|
||||
final Element property = addProperty(
|
||||
parent,
|
||||
(modifiedFlagName != null) ? modifiedFlagName : getModifiedFlagPropertyName( propertyName, suffix ),
|
||||
"boolean",
|
||||
true,
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
addColumn( property, columnName, null, null, null, null, null, null );
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
public static String getModifiedFlagPropertyName(String propertyName, String suffix) {
|
||||
return propertyName + suffix;
|
||||
}
|
||||
|
|
|
@ -590,13 +590,9 @@ public class AuditedPropertiesReader {
|
|||
propertyData.setStore( aud.modStore() );
|
||||
propertyData.setRelationTargetAuditMode( aud.targetAuditMode() );
|
||||
propertyData.setUsingModifiedFlag( checkUsingModifiedFlag( aud ) );
|
||||
propertyData.setModifiedFlagName( MetadataTools.getModifiedFlagPropertyName( propertyName, modifiedFlagSuffix ) );
|
||||
if( aud.modifiedColumnName() != null && !"".equals( aud.modifiedColumnName() ) ) {
|
||||
propertyData.setModifiedFlagName( aud.modifiedColumnName() );
|
||||
}
|
||||
else {
|
||||
propertyData.setModifiedFlagName(
|
||||
MetadataTools.getModifiedFlagPropertyName( propertyName, modifiedFlagSuffix )
|
||||
);
|
||||
propertyData.setExplicitModifiedFlagName( aud.modifiedColumnName() );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -44,13 +44,9 @@ public class ComponentAuditedPropertiesReader extends AuditedPropertiesReader {
|
|||
propertyData.setStore( aud.modStore() );
|
||||
propertyData.setRelationTargetAuditMode( aud.targetAuditMode() );
|
||||
propertyData.setUsingModifiedFlag( checkUsingModifiedFlag( aud ) );
|
||||
propertyData.setModifiedFlagName( MetadataTools.getModifiedFlagPropertyName( propertyName, modifiedFlagSuffix ) );
|
||||
if( aud.modifiedColumnName() != null && !"".equals( aud.modifiedColumnName() ) ) {
|
||||
propertyData.setModifiedFlagName( aud.modifiedColumnName() );
|
||||
}
|
||||
else {
|
||||
propertyData.setModifiedFlagName(
|
||||
MetadataTools.getModifiedFlagPropertyName( propertyName, modifiedFlagSuffix )
|
||||
);
|
||||
propertyData.setExplicitModifiedFlagName( aud.modifiedColumnName() );
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.hibernate.envers.AuditOverrides;
|
|||
import org.hibernate.envers.ModificationStore;
|
||||
import org.hibernate.envers.RelationTargetAuditMode;
|
||||
import org.hibernate.envers.internal.entities.PropertyData;
|
||||
import org.hibernate.envers.internal.tools.StringTools;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
|
@ -41,6 +42,7 @@ public class PropertyAuditingData {
|
|||
private boolean forceInsertable;
|
||||
private boolean usingModifiedFlag;
|
||||
private String modifiedFlagName;
|
||||
private String explicitModifiedFlagName;
|
||||
private Value value;
|
||||
// Synthetic properties are ones which are not part of the actual java model.
|
||||
// They're properties used for bookkeeping by Hibernate
|
||||
|
@ -237,6 +239,18 @@ public class PropertyAuditingData {
|
|||
this.modifiedFlagName = modifiedFlagName;
|
||||
}
|
||||
|
||||
public boolean isModifiedFlagNameExplicitlySpecified() {
|
||||
return !StringTools.isEmpty( explicitModifiedFlagName );
|
||||
}
|
||||
|
||||
public String getExplicitModifiedFlagName() {
|
||||
return explicitModifiedFlagName;
|
||||
}
|
||||
|
||||
public void setExplicitModifiedFlagName(String modifiedFlagName) {
|
||||
this.explicitModifiedFlagName = modifiedFlagName;
|
||||
}
|
||||
|
||||
public void addAuditingOverride(AuditOverride annotation) {
|
||||
if ( annotation != null ) {
|
||||
final String overrideName = annotation.name();
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#
|
||||
# Hibernate, Relational Persistence for Idiomatic Java
|
||||
#
|
||||
# License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
# See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
#
|
||||
#
|
||||
# Hibernate, Relational Persistence for Idiomatic Java
|
||||
#
|
||||
# License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
# See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
#
|
||||
org.hibernate.envers.boot.internal.ModifiedColumnNamingStrategyRegistrationProvider
|
|
@ -21,5 +21,8 @@
|
|||
|
||||
<bean id="additionalJaxbMappingProducer" class="org.hibernate.envers.boot.internal.AdditionalJaxbMappingProducerImpl"/>
|
||||
<service ref="additionalJaxbMappingProducer" interface="org.hibernate.boot.spi.AdditionalJaxbMappingProducer"/>
|
||||
|
||||
|
||||
<bean id="modifiedColumnNamingStrategyRegistrationProducer" class="org.hibernate.envers.boot.internal.ModifiedColumnNamingStrategyRegistrationProvider"/>
|
||||
<service ref="modifiedColumnNamingStrategyRegistrationProducer" interface="org.hibernate.boot.registry.selector.StrategyRegistrationProvider"/>
|
||||
|
||||
</blueprint>
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.envers.test.integration.modifiedflags.naming;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.envers.configuration.EnversSettings;
|
||||
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
public class ImprovedColumnNamingStrategyTest extends BaseEnversJPAFunctionalTestCase {
|
||||
@Override
|
||||
protected void addConfigOptions(Map options) {
|
||||
super.addConfigOptions( options );
|
||||
|
||||
options.put( EnversSettings.MODIFIED_COLUMN_NAMING_STRATEGY, "improved" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] { TestEntity.class, OtherEntity.class, SingleIdEntity.class };
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testModifiedColumns() {
|
||||
final Table table1 = metadata().getEntityBinding( TestEntity.class.getName() + "_AUD" ).getTable();
|
||||
assertNotNull( table1.getColumn( new Column( "data1_MOD") ) );
|
||||
assertNotNull( table1.getColumn( new Column( "mydata_MOD" ) ) );
|
||||
assertNotNull( table1.getColumn( new Column( "data_3" ) ) );
|
||||
assertNotNull( table1.getColumn( new Column( "the_data_mod" ) ) );
|
||||
|
||||
assertNotNull( table1.getColumn( new Column( "embeddable_MOD" ) ) );
|
||||
assertNotNull( table1.getColumn( new Column( "otherEntity_MOD" ) ) );
|
||||
assertNotNull( table1.getColumn( new Column( "single_id_MOD" ) ) );
|
||||
assertNotNull( table1.getColumn( new Column( "singleIdEntity2_id_MOD" ) ) );
|
||||
|
||||
final Table table2 = metadata().getEntityBinding( OtherEntity.class.getName() + "_AUD" ).getTable();
|
||||
assertNotNull( table2.getColumn( new Column( "d_MOD" ) ) );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.envers.test.integration.modifiedflags.naming;
|
||||
|
||||
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
public class LegacyColumnNamingStrategyTest extends BaseEnversJPAFunctionalTestCase {
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] { TestEntity.class, OtherEntity.class, SingleIdEntity.class };
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testModifiedColumns() {
|
||||
final Table table1 = metadata().getEntityBinding( TestEntity.class.getName() + "_AUD" ).getTable();
|
||||
assertNotNull( table1.getColumn( new Column( "data1_MOD") ) );
|
||||
assertNotNull( table1.getColumn( new Column( "data2_MOD" ) ) );
|
||||
assertNotNull( table1.getColumn( new Column( "data_3" ) ) );
|
||||
assertNotNull( table1.getColumn( new Column( "the_data_mod" ) ) );
|
||||
|
||||
assertNotNull( table1.getColumn( new Column( "embeddable_MOD" ) ) );
|
||||
assertNotNull( table1.getColumn( new Column( "otherEntity_MOD" ) ) );
|
||||
assertNotNull( table1.getColumn( new Column( "singleIdEntity_MOD" ) ) );
|
||||
assertNotNull( table1.getColumn( new Column( "singleIdEntity2_MOD" ) ) );
|
||||
|
||||
final Table table2 = metadata().getEntityBinding( OtherEntity.class.getName() + "_AUD" ).getTable();
|
||||
assertNotNull( table2.getColumn( new Column( "data_MOD" ) ) );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.envers.test.integration.modifiedflags.naming;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Entity;
|
||||
|
||||
import org.hibernate.envers.Audited;
|
||||
|
||||
/**
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
@Entity
|
||||
@Audited(withModifiedFlag = true)
|
||||
public class OtherEntity {
|
||||
@EmbeddedId
|
||||
private OtherEntityId id;
|
||||
|
||||
@Column(name = "d")
|
||||
private String data;
|
||||
|
||||
public OtherEntityId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(OtherEntityId id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.envers.test.integration.modifiedflags.naming;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.Embeddable;
|
||||
|
||||
/**
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
@Embeddable
|
||||
public class OtherEntityId implements Serializable {
|
||||
private Integer id1;
|
||||
private Integer id2;
|
||||
|
||||
public Integer getId1() {
|
||||
return id1;
|
||||
}
|
||||
|
||||
public void setId1(Integer id1) {
|
||||
this.id1 = id1;
|
||||
}
|
||||
|
||||
public Integer getId2() {
|
||||
return id2;
|
||||
}
|
||||
|
||||
public void setId2(Integer id2) {
|
||||
this.id2 = id2;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.envers.test.integration.modifiedflags.naming;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.envers.Audited;
|
||||
|
||||
/**
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
@Entity
|
||||
@Audited(withModifiedFlag = true)
|
||||
public class SingleIdEntity {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.envers.test.integration.modifiedflags.naming;
|
||||
|
||||
import javax.persistence.Embeddable;
|
||||
|
||||
/**
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
@Embeddable
|
||||
public class TestEmbeddable {
|
||||
String value1;
|
||||
String value2;
|
||||
|
||||
public String getValue1() {
|
||||
return value1;
|
||||
}
|
||||
|
||||
public void setValue1(String value1) {
|
||||
this.value1 = value1;
|
||||
}
|
||||
|
||||
public String getValue2() {
|
||||
return value2;
|
||||
}
|
||||
|
||||
public void setValue2(String value2) {
|
||||
this.value2 = value2;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.envers.test.integration.modifiedflags.naming;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinColumns;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToOne;
|
||||
|
||||
import org.hibernate.envers.Audited;
|
||||
|
||||
/**
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
@Entity
|
||||
@Audited(withModifiedFlag = true)
|
||||
public class TestEntity {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Integer id;
|
||||
private String data1;
|
||||
@Column(name = "mydata")
|
||||
private String data2;
|
||||
@Audited(modifiedColumnName = "data_3", withModifiedFlag = true)
|
||||
private String data3;
|
||||
@Column(name = "thedata")
|
||||
@Audited(modifiedColumnName = "the_data_mod", withModifiedFlag = true)
|
||||
private String data4;
|
||||
@Embedded
|
||||
private TestEmbeddable embeddable;
|
||||
@ManyToOne
|
||||
@JoinColumns({
|
||||
@JoinColumn(name = "other_entity_id1", nullable = false),
|
||||
@JoinColumn(name = "other_entity_id2", nullable = false)
|
||||
})
|
||||
private OtherEntity otherEntity;
|
||||
|
||||
@OneToOne
|
||||
@JoinColumn(name = "single_id")
|
||||
private SingleIdEntity singleIdEntity;
|
||||
|
||||
@OneToOne
|
||||
private SingleIdEntity singleIdEntity2;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getData1() {
|
||||
return data1;
|
||||
}
|
||||
|
||||
public void setData1(String data1) {
|
||||
this.data1 = data1;
|
||||
}
|
||||
|
||||
public String getData2() {
|
||||
return data2;
|
||||
}
|
||||
|
||||
public void setData2(String data2) {
|
||||
this.data2 = data2;
|
||||
}
|
||||
|
||||
public String getData3() {
|
||||
return data3;
|
||||
}
|
||||
|
||||
public void setData3(String data3) {
|
||||
this.data3 = data3;
|
||||
}
|
||||
|
||||
public String getData4() {
|
||||
return data4;
|
||||
}
|
||||
|
||||
public void setData4(String data4) {
|
||||
this.data4 = data4;
|
||||
}
|
||||
|
||||
public TestEmbeddable getEmbeddable() {
|
||||
return embeddable;
|
||||
}
|
||||
|
||||
public void setEmbeddable(TestEmbeddable embeddable) {
|
||||
this.embeddable = embeddable;
|
||||
}
|
||||
|
||||
public OtherEntity getOtherEntity() {
|
||||
return otherEntity;
|
||||
}
|
||||
|
||||
public void setOtherEntity(OtherEntity otherEntity) {
|
||||
this.otherEntity = otherEntity;
|
||||
}
|
||||
|
||||
public SingleIdEntity getSingleIdEntity() {
|
||||
return singleIdEntity;
|
||||
}
|
||||
|
||||
public void setSingleIdEntity(SingleIdEntity singleIdEntity) {
|
||||
this.singleIdEntity = singleIdEntity;
|
||||
}
|
||||
|
||||
public SingleIdEntity getSingleIdEntity2() {
|
||||
return singleIdEntity2;
|
||||
}
|
||||
|
||||
public void setSingleIdEntity2(SingleIdEntity singleIdEntity2) {
|
||||
this.singleIdEntity2 = singleIdEntity2;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue