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".
|
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` )::
|
`*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.
|
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.track_entities_changed_in_revision`
|
||||||
. `org.hibernate.envers.using_modified_flag`
|
. `org.hibernate.envers.using_modified_flag`
|
||||||
. `org.hibernate.envers.modified_flag_suffix`
|
. `org.hibernate.envers.modified_flag_suffix`
|
||||||
|
. `org.hibernate.envers.modified_column_naming_strategy`
|
||||||
. `org.hibernate.envers.original_id_prop_name`
|
. `org.hibernate.envers.original_id_prop_name`
|
||||||
. `org.hibernate.envers.find_by_revision_exact_match`
|
. `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>>.
|
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]]
|
[[envers-queries]]
|
||||||
=== Queries
|
=== Queries
|
||||||
|
|
||||||
|
|
|
@ -285,21 +285,21 @@ public class DefaultLoadEventListener implements LoadEventListener {
|
||||||
|
|
||||||
LazyInitializer li = ( (HibernateProxy) proxy ).getHibernateLazyInitializer();
|
LazyInitializer li = ( (HibernateProxy) proxy ).getHibernateLazyInitializer();
|
||||||
|
|
||||||
if ( li.isUnwrap() || event.getShouldUnwrapProxy() ) {
|
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 li.getImplementation();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return persistenceContext.narrowProxy( proxy, persister, keyToLoad, null );
|
return persistenceContext.narrowProxy( proxy, persister, keyToLoad, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
// specialized handling for entities with subclasses with a HibernateProxy factory
|
// specialized handling for entities with subclasses with a HibernateProxy factory
|
||||||
if ( entityMetamodel.hasSubclasses() ) {
|
if ( entityMetamodel.hasSubclasses() ) {
|
||||||
// entities with subclasses that define a ProxyFactory can create
|
// entities with subclasses that define a ProxyFactory can create a HibernateProxy
|
||||||
// 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" );
|
|
||||||
}
|
|
||||||
return createProxy( event, persister, keyToLoad, persistenceContext );
|
return createProxy( event, persister, keyToLoad, persistenceContext );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,8 +47,6 @@ public class LoadEvent extends AbstractEvent {
|
||||||
private Object result;
|
private Object result;
|
||||||
private PostLoadEvent postLoadEvent;
|
private PostLoadEvent postLoadEvent;
|
||||||
|
|
||||||
private Boolean shouldUnwrapProxy;
|
|
||||||
|
|
||||||
public LoadEvent(Serializable entityId, Object instanceToLoad, EventSource source) {
|
public LoadEvent(Serializable entityId, Object instanceToLoad, EventSource source) {
|
||||||
this( entityId, null, instanceToLoad, DEFAULT_LOCK_OPTIONS, false, source );
|
this( entityId, null, instanceToLoad, DEFAULT_LOCK_OPTIONS, false, source );
|
||||||
}
|
}
|
||||||
|
@ -192,19 +190,4 @@ public class LoadEvent extends AbstractEvent {
|
||||||
public void setPostLoadEvent(PostLoadEvent postLoadEvent) {
|
public void setPostLoadEvent(PostLoadEvent postLoadEvent) {
|
||||||
this.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;
|
loadEvent = null;
|
||||||
|
|
||||||
event = recycleEventInstance( event, id, entityName );
|
event = recycleEventInstance( event, id, entityName );
|
||||||
event.setShouldUnwrapProxy( unwrapProxy );
|
|
||||||
|
|
||||||
fireLoadNoChecks( event, type );
|
fireLoadNoChecks( event, type );
|
||||||
|
|
||||||
|
@ -1054,7 +1053,6 @@ public final class SessionImpl
|
||||||
event.setLockMode( LoadEvent.DEFAULT_LOCK_MODE );
|
event.setLockMode( LoadEvent.DEFAULT_LOCK_MODE );
|
||||||
event.setLockScope( LoadEvent.DEFAULT_LOCK_OPTIONS.getScope() );
|
event.setLockScope( LoadEvent.DEFAULT_LOCK_OPTIONS.getScope() );
|
||||||
event.setLockTimeout( LoadEvent.DEFAULT_LOCK_OPTIONS.getTimeOut() );
|
event.setLockTimeout( LoadEvent.DEFAULT_LOCK_OPTIONS.getTimeOut() );
|
||||||
event.setShouldUnwrapProxy( null );
|
|
||||||
return event;
|
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;
|
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.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.logging.Logger;
|
|
||||||
import javax.persistence.EntityManagerFactory;
|
import javax.persistence.EntityManagerFactory;
|
||||||
import javax.persistence.spi.PersistenceProvider;
|
import javax.persistence.spi.PersistenceProvider;
|
||||||
import javax.persistence.spi.PersistenceUnitInfo;
|
import javax.persistence.spi.PersistenceUnitInfo;
|
||||||
|
@ -100,7 +96,7 @@ public class PersistenceUnitOverridesTests extends BaseUnitTestCase {
|
||||||
final Properties puProperties;
|
final Properties puProperties;
|
||||||
|
|
||||||
{
|
{
|
||||||
puDataSource = new DataSourceImpl( "puDataSource" );
|
puDataSource = new DataSourceStub( "puDataSource" );
|
||||||
|
|
||||||
puProperties = new Properties();
|
puProperties = new Properties();
|
||||||
puProperties.putAll( info.getProperties() );
|
puProperties.putAll( info.getProperties() );
|
||||||
|
@ -161,7 +157,7 @@ public class PersistenceUnitOverridesTests extends BaseUnitTestCase {
|
||||||
final DataSource puDataSource;
|
final DataSource puDataSource;
|
||||||
|
|
||||||
{
|
{
|
||||||
puDataSource = new DataSourceImpl( "puDataSource" );
|
puDataSource = new DataSourceStub( "puDataSource" );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -209,8 +205,8 @@ public class PersistenceUnitOverridesTests extends BaseUnitTestCase {
|
||||||
"have precedence over integration settings, which is also incorrect"
|
"have precedence over integration settings, which is also incorrect"
|
||||||
)
|
)
|
||||||
public void testPassingIntegrationJpaDataSourceOverrideForJtaDataSourceElement() {
|
public void testPassingIntegrationJpaDataSourceOverrideForJtaDataSourceElement() {
|
||||||
final DataSource puDataSource = new DataSourceImpl( "puDataSource" );
|
final DataSource puDataSource = new DataSourceStub( "puDataSource" );
|
||||||
final DataSource integrationDataSource = new DataSourceImpl( "integrationDataSource" );
|
final DataSource integrationDataSource = new DataSourceStub( "integrationDataSource" );
|
||||||
|
|
||||||
PersistenceProvider provider = new HibernatePersistenceProvider() {
|
PersistenceProvider provider = new HibernatePersistenceProvider() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -263,7 +259,7 @@ public class PersistenceUnitOverridesTests extends BaseUnitTestCase {
|
||||||
public void testIntegrationOverridesOfPersistenceXmlDataSource() {
|
public void testIntegrationOverridesOfPersistenceXmlDataSource() {
|
||||||
|
|
||||||
// mimics a DataSource defined in the persistence.xml
|
// 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() {
|
final PersistenceUnitInfoAdapter info = new PersistenceUnitInfoAdapter() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -274,7 +270,7 @@ public class PersistenceUnitOverridesTests extends BaseUnitTestCase {
|
||||||
|
|
||||||
|
|
||||||
// Now create "integration Map" that overrides the DataSource to use
|
// 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<>();
|
final Map<String,Object> integrationSettings = new HashMap<>();
|
||||||
integrationSettings.put( AvailableSettings.JPA_NON_JTA_DATASOURCE, override );
|
integrationSettings.put( AvailableSettings.JPA_NON_JTA_DATASOURCE, override );
|
||||||
|
|
||||||
|
@ -308,7 +304,7 @@ public class PersistenceUnitOverridesTests extends BaseUnitTestCase {
|
||||||
public void testIntegrationOverridesOfPersistenceXmlDataSourceWithDriverManagerInfo() {
|
public void testIntegrationOverridesOfPersistenceXmlDataSourceWithDriverManagerInfo() {
|
||||||
|
|
||||||
// mimics a DataSource defined in the persistence.xml
|
// 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() {
|
final PersistenceUnitInfoAdapter info = new PersistenceUnitInfoAdapter() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -335,71 +331,4 @@ public class PersistenceUnitOverridesTests extends BaseUnitTestCase {
|
||||||
assertThat( connectionProvider, instanceOf( DriverManagerConnectionProviderImpl.class ) );
|
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.SessionFactoryBuilder;
|
||||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
|
|
||||||
import org.hibernate.testing.FailureExpected;
|
import org.hibernate.testing.FailureExpected;
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
@ -63,7 +64,6 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@FailureExpected( jiraKey = "HHH-13640")
|
|
||||||
public void testNewProxyAssociation() {
|
public void testNewProxyAssociation() {
|
||||||
inTransaction(
|
inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
|
@ -80,6 +80,7 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
|
||||||
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
|
||||||
assertFalse( Hibernate.isInitialized( otherEntity.animal ) );
|
assertFalse( Hibernate.isInitialized( otherEntity.animal ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.animal ) );
|
||||||
Animal animal = session.load( Animal.class, "A Human" );
|
Animal animal = session.load( Animal.class, "A Human" );
|
||||||
assertFalse( Hibernate.isInitialized( animal ) );
|
assertFalse( Hibernate.isInitialized( animal ) );
|
||||||
}
|
}
|
||||||
|
@ -87,8 +88,7 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@FailureExpected( jiraKey = "HHH-13640")
|
public void testExistingProxyAssociation() {
|
||||||
public void testReusedProxyAssociation() {
|
|
||||||
inTransaction(
|
inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
Human human = new Human( "A Human" );
|
Human human = new Human( "A Human" );
|
||||||
|
@ -105,8 +105,43 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
|
||||||
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
|
||||||
assertFalse( Hibernate.isInitialized( otherEntity.animal ) );
|
assertFalse( Hibernate.isInitialized( otherEntity.animal ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.animal ) );
|
||||||
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "primate" ) );
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "primate" ) );
|
||||||
assertFalse( Hibernate.isInitialized( 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
|
* @since 5.4.4
|
||||||
*/
|
*/
|
||||||
String FIND_BY_REVISION_EXACT_MATCH = "org.hibernate.envers.find_by_revision_exact_match";
|
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;
|
package org.hibernate.envers.configuration.internal;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
|
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
|
||||||
|
import org.hibernate.boot.registry.selector.spi.StrategySelector;
|
||||||
import org.hibernate.cfg.Environment;
|
import org.hibernate.cfg.Environment;
|
||||||
import org.hibernate.dialect.HSQLDialect;
|
import org.hibernate.dialect.HSQLDialect;
|
||||||
import org.hibernate.envers.RevisionListener;
|
import org.hibernate.envers.RevisionListener;
|
||||||
import org.hibernate.envers.boot.internal.EnversService;
|
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.configuration.EnversSettings;
|
||||||
import org.hibernate.envers.internal.tools.ReflectionTools;
|
import org.hibernate.envers.internal.tools.ReflectionTools;
|
||||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||||
|
@ -77,11 +81,15 @@ public class GlobalConfiguration {
|
||||||
*/
|
*/
|
||||||
private final String correlatedSubqueryOperator;
|
private final String correlatedSubqueryOperator;
|
||||||
|
|
||||||
|
private final ModifiedColumnNamingStrategy modifiedColumnNamingStrategy;
|
||||||
|
|
||||||
public GlobalConfiguration(
|
public GlobalConfiguration(
|
||||||
EnversService enversService,
|
EnversService enversService,
|
||||||
Map properties) {
|
Map properties) {
|
||||||
this.enversService = enversService;
|
this.enversService = enversService;
|
||||||
|
|
||||||
|
final StrategySelector strategySelector = enversService.getServiceRegistry().getService( StrategySelector.class );
|
||||||
|
|
||||||
generateRevisionsForCollections = ConfigurationHelper.getBoolean(
|
generateRevisionsForCollections = ConfigurationHelper.getBoolean(
|
||||||
EnversSettings.REVISION_ON_COLLECTION_CHANGE,
|
EnversSettings.REVISION_ON_COLLECTION_CHANGE,
|
||||||
properties,
|
properties,
|
||||||
|
@ -156,6 +164,21 @@ public class GlobalConfiguration {
|
||||||
revisionListenerClass = null;
|
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(
|
allowIdentifierReuse = ConfigurationHelper.getBoolean(
|
||||||
EnversSettings.ALLOW_IDENTIFIER_REUSE, properties, false
|
EnversSettings.ALLOW_IDENTIFIER_REUSE, properties, false
|
||||||
);
|
);
|
||||||
|
@ -232,4 +255,8 @@ public class GlobalConfiguration {
|
||||||
public boolean isAuditReaderFindAtRevisionExactMatch() {
|
public boolean isAuditReaderFindAtRevisionExactMatch() {
|
||||||
return findByRevisionExactMatch;
|
return findByRevisionExactMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ModifiedColumnNamingStrategy getModifiedColumnNamingStrategy() {
|
||||||
|
return modifiedColumnNamingStrategy;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,7 +213,7 @@ public final class AuditMetadataGenerator {
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
addModifiedFlagIfNeeded( parent, propertyAuditingData, processModifiedFlag );
|
addModifiedFlagIfNeeded( value, parent, propertyAuditingData, processModifiedFlag );
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean processedInSecondPass(Type type) {
|
private boolean processedInSecondPass(Type type) {
|
||||||
|
@ -290,19 +290,20 @@ public final class AuditMetadataGenerator {
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
addModifiedFlagIfNeeded( parent, propertyAuditingData, processModifiedFlag );
|
addModifiedFlagIfNeeded( value, parent, propertyAuditingData, processModifiedFlag );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addModifiedFlagIfNeeded(
|
private void addModifiedFlagIfNeeded(
|
||||||
|
Value value,
|
||||||
Element parent,
|
Element parent,
|
||||||
PropertyAuditingData propertyAuditingData,
|
PropertyAuditingData propertyAuditingData,
|
||||||
boolean processModifiedFlag) {
|
boolean processModifiedFlag) {
|
||||||
if ( processModifiedFlag && propertyAuditingData.isUsingModifiedFlag() ) {
|
if ( processModifiedFlag && propertyAuditingData.isUsingModifiedFlag() ) {
|
||||||
MetadataTools.addModifiedFlagProperty(
|
globalCfg.getModifiedColumnNamingStrategy().addModifiedColumns(
|
||||||
|
globalCfg,
|
||||||
|
value,
|
||||||
parent,
|
parent,
|
||||||
propertyAuditingData.getName(),
|
propertyAuditingData
|
||||||
globalCfg.getModifiedFlagSuffix(),
|
|
||||||
propertyAuditingData.getModifiedFlagName()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
public static String getModifiedFlagPropertyName(String propertyName, String suffix) {
|
||||||
return propertyName + suffix;
|
return propertyName + suffix;
|
||||||
}
|
}
|
||||||
|
|
|
@ -590,13 +590,9 @@ public class AuditedPropertiesReader {
|
||||||
propertyData.setStore( aud.modStore() );
|
propertyData.setStore( aud.modStore() );
|
||||||
propertyData.setRelationTargetAuditMode( aud.targetAuditMode() );
|
propertyData.setRelationTargetAuditMode( aud.targetAuditMode() );
|
||||||
propertyData.setUsingModifiedFlag( checkUsingModifiedFlag( aud ) );
|
propertyData.setUsingModifiedFlag( checkUsingModifiedFlag( aud ) );
|
||||||
|
propertyData.setModifiedFlagName( MetadataTools.getModifiedFlagPropertyName( propertyName, modifiedFlagSuffix ) );
|
||||||
if( aud.modifiedColumnName() != null && !"".equals( aud.modifiedColumnName() ) ) {
|
if( aud.modifiedColumnName() != null && !"".equals( aud.modifiedColumnName() ) ) {
|
||||||
propertyData.setModifiedFlagName( aud.modifiedColumnName() );
|
propertyData.setExplicitModifiedFlagName( aud.modifiedColumnName() );
|
||||||
}
|
|
||||||
else {
|
|
||||||
propertyData.setModifiedFlagName(
|
|
||||||
MetadataTools.getModifiedFlagPropertyName( propertyName, modifiedFlagSuffix )
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,13 +44,9 @@ public class ComponentAuditedPropertiesReader extends AuditedPropertiesReader {
|
||||||
propertyData.setStore( aud.modStore() );
|
propertyData.setStore( aud.modStore() );
|
||||||
propertyData.setRelationTargetAuditMode( aud.targetAuditMode() );
|
propertyData.setRelationTargetAuditMode( aud.targetAuditMode() );
|
||||||
propertyData.setUsingModifiedFlag( checkUsingModifiedFlag( aud ) );
|
propertyData.setUsingModifiedFlag( checkUsingModifiedFlag( aud ) );
|
||||||
|
propertyData.setModifiedFlagName( MetadataTools.getModifiedFlagPropertyName( propertyName, modifiedFlagSuffix ) );
|
||||||
if( aud.modifiedColumnName() != null && !"".equals( aud.modifiedColumnName() ) ) {
|
if( aud.modifiedColumnName() != null && !"".equals( aud.modifiedColumnName() ) ) {
|
||||||
propertyData.setModifiedFlagName( aud.modifiedColumnName() );
|
propertyData.setExplicitModifiedFlagName( aud.modifiedColumnName() );
|
||||||
}
|
|
||||||
else {
|
|
||||||
propertyData.setModifiedFlagName(
|
|
||||||
MetadataTools.getModifiedFlagPropertyName( propertyName, modifiedFlagSuffix )
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -17,6 +17,7 @@ import org.hibernate.envers.AuditOverrides;
|
||||||
import org.hibernate.envers.ModificationStore;
|
import org.hibernate.envers.ModificationStore;
|
||||||
import org.hibernate.envers.RelationTargetAuditMode;
|
import org.hibernate.envers.RelationTargetAuditMode;
|
||||||
import org.hibernate.envers.internal.entities.PropertyData;
|
import org.hibernate.envers.internal.entities.PropertyData;
|
||||||
|
import org.hibernate.envers.internal.tools.StringTools;
|
||||||
import org.hibernate.mapping.Value;
|
import org.hibernate.mapping.Value;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
|
@ -41,6 +42,7 @@ public class PropertyAuditingData {
|
||||||
private boolean forceInsertable;
|
private boolean forceInsertable;
|
||||||
private boolean usingModifiedFlag;
|
private boolean usingModifiedFlag;
|
||||||
private String modifiedFlagName;
|
private String modifiedFlagName;
|
||||||
|
private String explicitModifiedFlagName;
|
||||||
private Value value;
|
private Value value;
|
||||||
// Synthetic properties are ones which are not part of the actual java model.
|
// Synthetic properties are ones which are not part of the actual java model.
|
||||||
// They're properties used for bookkeeping by Hibernate
|
// They're properties used for bookkeeping by Hibernate
|
||||||
|
@ -237,6 +239,18 @@ public class PropertyAuditingData {
|
||||||
this.modifiedFlagName = modifiedFlagName;
|
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) {
|
public void addAuditingOverride(AuditOverride annotation) {
|
||||||
if ( annotation != null ) {
|
if ( annotation != null ) {
|
||||||
final String overrideName = annotation.name();
|
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
|
|
@ -22,4 +22,7 @@
|
||||||
<bean id="additionalJaxbMappingProducer" class="org.hibernate.envers.boot.internal.AdditionalJaxbMappingProducerImpl"/>
|
<bean id="additionalJaxbMappingProducer" class="org.hibernate.envers.boot.internal.AdditionalJaxbMappingProducerImpl"/>
|
||||||
<service ref="additionalJaxbMappingProducer" interface="org.hibernate.boot.spi.AdditionalJaxbMappingProducer"/>
|
<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>
|
</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