diff --git a/documentation/envers/src/main/docbook/en-US/content/configuration.xml b/documentation/envers/src/main/docbook/en-US/content/configuration.xml
index 1b050c230d..eac3afa3e5 100644
--- a/documentation/envers/src/main/docbook/en-US/content/configuration.xml
+++ b/documentation/envers/src/main/docbook/en-US/content/configuration.xml
@@ -218,4 +218,11 @@
please see for a description of the additional
@AuditJoinTable annotation that you'll probably want to use.
+
+
+ If you want to audit a relation, where the target entity is not audited (that is the case for example with
+ dictionary-like entities, which don't change and don't have to be audited), just annotate it with
+ @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED). Then, when reading historic
+ versions of your entity, the relation will always point to the "current" related entity.
+
diff --git a/envers/src/main/java/org/hibernate/envers/Audited.java b/envers/src/main/java/org/hibernate/envers/Audited.java
index b665677b11..01dc2134c1 100644
--- a/envers/src/main/java/org/hibernate/envers/Audited.java
+++ b/envers/src/main/java/org/hibernate/envers/Audited.java
@@ -32,9 +32,17 @@ import java.lang.annotation.Target;
* When applied to a class, indicates that all of its properties should be audited.
* When applied to a field, indicates that this field should be audited.
* @author Adam Warski (adam at warski dot org)
+ * @author Tomasz Bech
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
public @interface Audited {
ModificationStore modStore() default ModificationStore.FULL;
+
+ /**
+ * @return Specifies if the entity that is the target of the relation should be audited or not. If not, then when
+ * reading a historic version an audited entity, the realtion will always point to the "current" entity.
+ * This is useful for dictionary-like entities, which don't change and don't need to be audited.
+ */
+ RelationTargetAuditMode targetAuditMode() default RelationTargetAuditMode.AUDITED;
}
diff --git a/envers/src/main/java/org/hibernate/envers/RelationTargetAuditMode.java b/envers/src/main/java/org/hibernate/envers/RelationTargetAuditMode.java
new file mode 100644
index 0000000000..b4216f7298
--- /dev/null
+++ b/envers/src/main/java/org/hibernate/envers/RelationTargetAuditMode.java
@@ -0,0 +1,32 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.envers;
+
+/**
+ * @author Tomasz Bech
+ */
+public enum RelationTargetAuditMode {
+ AUDITED,
+ NOT_AUDITED
+}
diff --git a/envers/src/main/java/org/hibernate/envers/configuration/EntitiesConfigurator.java b/envers/src/main/java/org/hibernate/envers/configuration/EntitiesConfigurator.java
index b858e9807a..47539b1bda 100644
--- a/envers/src/main/java/org/hibernate/envers/configuration/EntitiesConfigurator.java
+++ b/envers/src/main/java/org/hibernate/envers/configuration/EntitiesConfigurator.java
@@ -84,9 +84,13 @@ public class EntitiesConfigurator {
}
EntityXmlMappingData xmlMappingData = new EntityXmlMappingData();
- auditMetaGen.generateFirstPass(pc, auditData, xmlMappingData);
+ auditMetaGen.generateFirstPass(pc, auditData, xmlMappingData, true);
xmlMappings.put(pc, xmlMappingData);
- }
+ } else {
+ EntityXmlMappingData xmlMappingData = new EntityXmlMappingData();
+ auditMetaGen.generateFirstPass(pc, auditData, xmlMappingData, false);
+ xmlMappings.put(pc, xmlMappingData);
+ }
}
// Second pass
@@ -123,7 +127,8 @@ public class EntitiesConfigurator {
}
}
- return new EntitiesConfigurations(auditMetaGen.getEntitiesConfigurations());
+ return new EntitiesConfigurations(auditMetaGen.getEntitiesConfigurations(),
+ auditMetaGen.getNotAuditedEntitiesConfigurations());
}
// todo
diff --git a/envers/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java b/envers/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java
index 4761f1a328..762f82431e 100644
--- a/envers/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java
+++ b/envers/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java
@@ -53,6 +53,7 @@ import org.hibernate.type.*;
/**
* @author Adam Warski (adam at warski dot org)
* @author Sebastian Komander
+ * @author Tomasz Bech
*/
public final class AuditMetadataGenerator {
private final Configuration cfg;
@@ -66,6 +67,7 @@ public final class AuditMetadataGenerator {
private final ToOneRelationMetadataGenerator toOneRelationMetadataGenerator;
private final Map entitiesConfigurations;
+ private final Map notAuditedEntitiesConfigurations;
// Map entity name -> (join descriptor -> element describing the "versioned" join)
private final Map> entitiesJoins;
@@ -84,6 +86,7 @@ public final class AuditMetadataGenerator {
this.toOneRelationMetadataGenerator = new ToOneRelationMetadataGenerator(this);
entitiesConfigurations = new HashMap();
+ notAuditedEntitiesConfigurations = new HashMap();
entitiesJoins = new HashMap>();
}
@@ -278,7 +281,7 @@ public final class AuditMetadataGenerator {
@SuppressWarnings({"unchecked"})
public void generateFirstPass(PersistentClass pc, ClassAuditingData auditingData,
- EntityXmlMappingData xmlMappingData) {
+ EntityXmlMappingData xmlMappingData, boolean isAudited) {
String schema = auditingData.getAuditTable().schema();
if (StringTools.isEmpty(schema)) {
schema = pc.getTable().getSchema();
@@ -289,6 +292,17 @@ public final class AuditMetadataGenerator {
catalog = pc.getTable().getCatalog();
}
+ if (!isAudited) {
+ String entityName = pc.getEntityName();
+ IdMappingData idMapper = idMetadataGenerator.addId(pc);
+ ExtendedPropertyMapper propertyMapper = null;
+ String parentEntityName = null;
+ EntityConfiguration entityCfg = new EntityConfiguration(entityName, idMapper, propertyMapper,
+ parentEntityName);
+ notAuditedEntitiesConfigurations.put(pc.getEntityName(), entityCfg);
+ return;
+ }
+
String entityName = pc.getEntityName();
String auditEntityName = verEntCfg.getAuditEntityName(entityName);
String auditTableName = verEntCfg.getAuditTableName(entityName, pc.getTable().getName());
@@ -400,4 +414,13 @@ public final class AuditMetadataGenerator {
throw new MappingException(message);
}
+
+ /**
+ * Get the notAuditedEntitiesConfigurations property.
+ *
+ * @return the notAuditedEntitiesConfigurations property value
+ */
+ public Map getNotAuditedEntitiesConfigurations() {
+ return notAuditedEntitiesConfigurations;
+ }
}
diff --git a/envers/src/main/java/org/hibernate/envers/configuration/metadata/CollectionMetadataGenerator.java b/envers/src/main/java/org/hibernate/envers/configuration/metadata/CollectionMetadataGenerator.java
index 1c7a987e43..d645fa2a20 100644
--- a/envers/src/main/java/org/hibernate/envers/configuration/metadata/CollectionMetadataGenerator.java
+++ b/envers/src/main/java/org/hibernate/envers/configuration/metadata/CollectionMetadataGenerator.java
@@ -36,6 +36,7 @@ import javax.persistence.JoinColumn;
import org.dom4j.Element;
import org.hibernate.envers.ModificationStore;
+import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData;
import org.hibernate.envers.entities.EntityConfiguration;
import org.hibernate.envers.entities.IdMappingData;
@@ -231,7 +232,7 @@ public final class CollectionMetadataGenerator {
// middle table for mapping this relation.
return StringTools.getLastComponent(entityName) + "_" + StringTools.getLastComponent(getReferencedEntityName(value.getElement()));
} else {
- // Hibernate uses a middle table for mapping this relation, so we get it's name directly.
+ // Hibernate uses a middle table for mapping this relation, so we get it's name directly.
return value.getCollectionTable().getName();
}
}
@@ -413,7 +414,7 @@ public final class CollectionMetadataGenerator {
} else {
// Last but one parameter: collection components are always insertable
boolean mapped = mainGenerator.getBasicMetadataGenerator().addBasic(xmlMapping,
- new PropertyAuditingData(prefix, "field", ModificationStore.FULL), value, null,
+ new PropertyAuditingData(prefix, "field", ModificationStore.FULL, RelationTargetAuditMode.AUDITED), value, null,
true, true);
if (mapped) {
diff --git a/envers/src/main/java/org/hibernate/envers/configuration/metadata/IdMetadataGenerator.java b/envers/src/main/java/org/hibernate/envers/configuration/metadata/IdMetadataGenerator.java
index 11583e6182..1b68c47790 100644
--- a/envers/src/main/java/org/hibernate/envers/configuration/metadata/IdMetadataGenerator.java
+++ b/envers/src/main/java/org/hibernate/envers/configuration/metadata/IdMetadataGenerator.java
@@ -28,6 +28,7 @@ import java.util.Iterator;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
import org.hibernate.envers.ModificationStore;
+import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData;
import org.hibernate.envers.entities.IdMappingData;
import org.hibernate.envers.entities.PropertyData;
@@ -133,6 +134,6 @@ public final class IdMetadataGenerator {
private PropertyAuditingData getIdPersistentPropertyAuditingData(Property property) {
return new PropertyAuditingData(property.getName(), property.getPropertyAccessorName(),
- ModificationStore.FULL);
+ ModificationStore.FULL, RelationTargetAuditMode.AUDITED);
}
}
diff --git a/envers/src/main/java/org/hibernate/envers/configuration/metadata/ToOneRelationMetadataGenerator.java b/envers/src/main/java/org/hibernate/envers/configuration/metadata/ToOneRelationMetadataGenerator.java
index 7cafc3a87a..e323477390 100644
--- a/envers/src/main/java/org/hibernate/envers/configuration/metadata/ToOneRelationMetadataGenerator.java
+++ b/envers/src/main/java/org/hibernate/envers/configuration/metadata/ToOneRelationMetadataGenerator.java
@@ -24,6 +24,7 @@
package org.hibernate.envers.configuration.metadata;
import org.dom4j.Element;
+import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.envers.entities.EntityConfiguration;
import org.hibernate.envers.entities.IdMappingData;
import org.hibernate.envers.entities.PropertyData;
@@ -54,10 +55,22 @@ public final class ToOneRelationMetadataGenerator {
CompositeMapperBuilder mapper, String entityName, boolean insertable) {
String referencedEntityName = ((ToOne) value).getReferencedEntityName();
- EntityConfiguration configuration = mainGenerator.getEntitiesConfigurations().get(referencedEntityName);
- if (configuration == null) {
- throw new MappingException("An audited relation to a non-audited entity " + referencedEntityName + "!");
- }
+ EntityConfiguration configuration = mainGenerator.getEntitiesConfigurations().get(referencedEntityName);
+ if (configuration == null) {
+ configuration = mainGenerator.getNotAuditedEntitiesConfigurations().get(referencedEntityName);
+ if (configuration != null) {
+ RelationTargetAuditMode relationTargetAuditMode = propertyAuditingData.getRelationTargetAuditMode();
+ if (!RelationTargetAuditMode.NOT_AUDITED.equals(relationTargetAuditMode)) {
+ throw new MappingException("An audited relation from " + entityName + "."
+ + propertyAuditingData.getName() + " to a not audited entity " + referencedEntityName + "!"
+ + ". Such mapping is possible, but has to be strictly defined using RelationTargetAuditMode.NOT_AUDITED in @Audited.");
+ }
+ }
+ }
+ if (configuration == null) {
+ throw new MappingException("An audited relation from " + entityName + "."
+ + propertyAuditingData.getName() + " to a not audited entity " + referencedEntityName + "!");
+ }
IdMappingData idMapping = configuration.getIdMappingData();
diff --git a/envers/src/main/java/org/hibernate/envers/configuration/metadata/reader/AuditedPropertiesReader.java b/envers/src/main/java/org/hibernate/envers/configuration/metadata/reader/AuditedPropertiesReader.java
index e5d92d1f12..ff6e37051b 100644
--- a/envers/src/main/java/org/hibernate/envers/configuration/metadata/reader/AuditedPropertiesReader.java
+++ b/envers/src/main/java/org/hibernate/envers/configuration/metadata/reader/AuditedPropertiesReader.java
@@ -160,6 +160,7 @@ public class AuditedPropertiesReader {
Versioned ver = property.getAnnotation(Versioned.class);
if (aud != null) {
propertyData.setStore(aud.modStore());
+ propertyData.setRelationTargetAuditMode(aud.targetAuditMode());
} else if (ver != null) {
propertyData.setStore(ModificationStore.FULL);
} else {
@@ -203,7 +204,7 @@ public class AuditedPropertiesReader {
/***
* Add the {@link org.hibernate.envers.AuditOverride} annotations.
- *
+ *
* @param property the property being processed
* @param propertyData the Envers auditing data for this property
*/
@@ -220,13 +221,13 @@ public class AuditedPropertiesReader {
/**
* Process the {@link org.hibernate.envers.AuditOverride} annotations for this property.
- *
+ *
* @param property
* the property for which the {@link org.hibernate.envers.AuditOverride}
* annotations are being processed
* @param propertyData
* the Envers auditing data for this property
- * @return {@code false} if isAudited() of the override annotation was set to
+ * @return {@code false} if isAudited() of the override annotation was set to
*/
private boolean processPropertyAuditingOverrides(XProperty property, PropertyAuditingData propertyData) {
// if this property is part of a component, process all override annotations
@@ -236,7 +237,7 @@ public class AuditedPropertiesReader {
if (property.getName().equals(override.name())) {
// the override applies to this property
if (!override.isAudited()) {
- return false;
+ return false;
} else {
if (override.auditJoinTable() != null) {
propertyData.setJoinTable(override.auditJoinTable());
@@ -267,7 +268,7 @@ public class AuditedPropertiesReader {
} catch (ClassNotFoundException e) {
throw new MappingException(e);
}
-
+
this.component = component;
}
diff --git a/envers/src/main/java/org/hibernate/envers/configuration/metadata/reader/PropertyAuditingData.java b/envers/src/main/java/org/hibernate/envers/configuration/metadata/reader/PropertyAuditingData.java
index 449b172ddf..3537e698d8 100644
--- a/envers/src/main/java/org/hibernate/envers/configuration/metadata/reader/PropertyAuditingData.java
+++ b/envers/src/main/java/org/hibernate/envers/configuration/metadata/reader/PropertyAuditingData.java
@@ -31,6 +31,7 @@ import org.hibernate.envers.AuditOverride;
import org.hibernate.envers.AuditOverrides;
import org.hibernate.envers.ModificationStore;
import org.hibernate.envers.AuditJoinTable;
+import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.envers.entities.PropertyData;
/**
@@ -44,15 +45,18 @@ public class PropertyAuditingData {
private AuditJoinTable joinTable;
private String accessType;
private final List auditJoinTableOverrides = new ArrayList(0);
+ private RelationTargetAuditMode relationTargetAuditMode;
- public PropertyAuditingData() {
+ public PropertyAuditingData() {
}
- public PropertyAuditingData(String name, String accessType, ModificationStore store) {
+ public PropertyAuditingData(String name, String accessType, ModificationStore store,
+ RelationTargetAuditMode relationTargetAuditMode) {
this.name = name;
this.beanName = name;
this.accessType = accessType;
this.store = store;
+ this.relationTargetAuditMode = relationTargetAuditMode;
}
public String getName() {
@@ -108,7 +112,7 @@ public class PropertyAuditingData {
}
public List getAuditingOverrides() {
- return auditJoinTableOverrides;
+ return auditJoinTableOverrides;
}
public void addAuditingOverride(AuditOverride annotation) {
@@ -135,4 +139,22 @@ public class PropertyAuditingData {
}
}
+ /**
+ * Get the relationTargetAuditMode property.
+ *
+ * @return the relationTargetAuditMode property value
+ */
+ public RelationTargetAuditMode getRelationTargetAuditMode() {
+ return relationTargetAuditMode;
+ }
+
+ /**
+ * Set the relationTargetAuditMode property value.
+ *
+ * @param relationTargetAuditMode the relationTargetAuditMode to set
+ */
+ public void setRelationTargetAuditMode(RelationTargetAuditMode relationTargetAuditMode) {
+ this.relationTargetAuditMode = relationTargetAuditMode;
+ }
+
}
diff --git a/envers/src/main/java/org/hibernate/envers/entities/EntitiesConfigurations.java b/envers/src/main/java/org/hibernate/envers/entities/EntitiesConfigurations.java
index 46f95b6880..de660e3aee 100644
--- a/envers/src/main/java/org/hibernate/envers/entities/EntitiesConfigurations.java
+++ b/envers/src/main/java/org/hibernate/envers/entities/EntitiesConfigurations.java
@@ -32,12 +32,15 @@ import java.util.Map;
*/
public class EntitiesConfigurations {
private Map entitiesConfigurations;
+ private Map notAuditedEntitiesConfigurations;
// Map versions entity name -> entity name
private Map entityNamesForVersionsEntityNames = new HashMap();
- public EntitiesConfigurations(Map entitiesConfigurations) {
+ public EntitiesConfigurations(Map entitiesConfigurations,
+ Map notAuditedEntitiesConfigurations) {
this.entitiesConfigurations = entitiesConfigurations;
+ this.notAuditedEntitiesConfigurations = notAuditedEntitiesConfigurations;
generateBidirectionRelationInfo();
generateVersionsEntityToEntityNames();
@@ -61,14 +64,17 @@ public class EntitiesConfigurations {
// If this is an "owned" relation, checking the related entity, if it has a relation that has
// a mapped-by attribute to the currently checked. If so, this is a bidirectional relation.
if (relDesc.getRelationType() == RelationType.TO_ONE ||
- relDesc.getRelationType() == RelationType.TO_MANY_MIDDLE) {
- for (RelationDescription other : entitiesConfigurations.get(relDesc.getToEntityName()).getRelationsIterator()) {
- if (relDesc.getFromPropertyName().equals(other.getMappedByPropertyName()) &&
- (entityName.equals(other.getToEntityName()))) {
- relDesc.setBidirectional(true);
- other.setBidirectional(true);
- }
- }
+ relDesc.getRelationType() == RelationType.TO_MANY_MIDDLE) {
+ EntityConfiguration entityConfiguration = entitiesConfigurations.get(relDesc.getToEntityName());
+ if (entityConfiguration != null) {
+ for (RelationDescription other : entityConfiguration.getRelationsIterator()) {
+ if (relDesc.getFromPropertyName().equals(other.getMappedByPropertyName()) &&
+ (entityName.equals(other.getToEntityName()))) {
+ relDesc.setBidirectional(true);
+ other.setBidirectional(true);
+ }
+ }
+ }
}
}
}
@@ -78,6 +84,10 @@ public class EntitiesConfigurations {
return entitiesConfigurations.get(entityName);
}
+ public EntityConfiguration getNotVersionEntityConfiguration(String entityName) {
+ return notAuditedEntitiesConfigurations.get(entityName);
+ }
+
public String getEntityNameForVersionsEntityName(String versionsEntityName) {
return entityNamesForVersionsEntityNames.get(versionsEntityName);
}
@@ -98,4 +108,5 @@ public class EntitiesConfigurations {
return null;
}
}
+
}
diff --git a/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/ToOneIdMapper.java b/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/ToOneIdMapper.java
index 149b81ae89..953cab2c66 100644
--- a/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/ToOneIdMapper.java
+++ b/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/ToOneIdMapper.java
@@ -82,7 +82,7 @@ public class ToOneIdMapper implements PropertyMapper {
Class> entityClass = ReflectionTools.loadClass(referencedEntityName);
value = versionsReader.getSessionImplementor().getFactory().getEntityPersister(referencedEntityName).
- createProxy(null, new ToOneDelegateSessionImplementor(versionsReader, entityClass, entityId, revision));
+ createProxy(null, new ToOneDelegateSessionImplementor(versionsReader, entityClass, entityId, revision, verCfg));
}
}
diff --git a/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/ToOneDelegateSessionImplementor.java b/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/ToOneDelegateSessionImplementor.java
index 5a88ab41e9..6446c64f73 100644
--- a/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/ToOneDelegateSessionImplementor.java
+++ b/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/ToOneDelegateSessionImplementor.java
@@ -23,29 +23,47 @@
*/
package org.hibernate.envers.entities.mapper.relation.lazy;
+import java.io.Serializable;
+
+import org.hibernate.envers.configuration.AuditConfiguration;
+import org.hibernate.envers.entities.EntitiesConfigurations;
+import org.hibernate.envers.entities.EntityConfiguration;
import org.hibernate.envers.reader.AuditReaderImplementor;
import org.hibernate.HibernateException;
+import org.hibernate.Session;
/**
* @author Adam Warski (adam at warski dot org)
+ * @author Tomasz Bech
*/
public class ToOneDelegateSessionImplementor extends AbstractDelegateSessionImplementor {
+ private static final long serialVersionUID = 4770438372940785488L;
+
private final AuditReaderImplementor versionsReader;
private final Class> entityClass;
private final Object entityId;
private final Number revision;
+ private EntityConfiguration notVersionedEntityConfiguration;
- public ToOneDelegateSessionImplementor(AuditReaderImplementor versionsReader,
- Class> entityClass, Object entityId, Number revision) {
+ public ToOneDelegateSessionImplementor(AuditReaderImplementor versionsReader,
+ Class> entityClass, Object entityId, Number revision,
+ AuditConfiguration verCfg) {
super(versionsReader.getSessionImplementor());
this.versionsReader = versionsReader;
this.entityClass = entityClass;
this.entityId = entityId;
this.revision = revision;
+ EntitiesConfigurations entCfg = verCfg.getEntCfg();
+ notVersionedEntityConfiguration = entCfg.getNotVersionEntityConfiguration(entityClass.getName());
}
public Object doImmediateLoad(String entityName) throws HibernateException {
- return versionsReader.find(entityClass, entityId, revision);
+ if (notVersionedEntityConfiguration == null) {
+ return versionsReader.find(entityClass, entityId, revision);
+ } else {
+ Session session = versionsReader.getSession();
+ return session.get(entityClass, (Serializable) entityId);
+ }
}
}
diff --git a/envers/src/test/java/org/hibernate/envers/test/entities/manytoone/unidirectional/TargetNotAuditedEntity.java b/envers/src/test/java/org/hibernate/envers/test/entities/manytoone/unidirectional/TargetNotAuditedEntity.java
new file mode 100644
index 0000000000..994cf3fbe9
--- /dev/null
+++ b/envers/src/test/java/org/hibernate/envers/test/entities/manytoone/unidirectional/TargetNotAuditedEntity.java
@@ -0,0 +1,115 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.envers.test.entities.manytoone.unidirectional;
+
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+
+import org.hibernate.envers.Audited;
+import org.hibernate.envers.RelationTargetAuditMode;
+import org.hibernate.envers.test.entities.UnversionedStrTestEntity;
+
+/**
+ * Audited entity with a reference to not audited entity.
+ * @author Toamsz Bech
+ */
+@Entity
+public class TargetNotAuditedEntity {
+ @Id
+ private Integer id;
+
+ @Audited
+ private String data;
+
+ @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
+ @ManyToOne(fetch = FetchType.EAGER)
+ private UnversionedStrTestEntity reference;
+
+ public TargetNotAuditedEntity() { }
+
+ public TargetNotAuditedEntity(Integer id, String data, UnversionedStrTestEntity reference) {
+ this.id = id;
+ this.data = data;
+ this.reference = reference;
+ }
+
+ public TargetNotAuditedEntity(String data, UnversionedStrTestEntity reference) {
+ this.data = data;
+ this.reference = reference;
+ }
+
+ public TargetNotAuditedEntity(Integer id, String data) {
+ this.id = id;
+ this.data = data;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getData() {
+ return data;
+ }
+
+ public void setData(String data) {
+ this.data = data;
+ }
+
+ public UnversionedStrTestEntity getReference() {
+ return reference;
+ }
+
+ public void setReference(UnversionedStrTestEntity reference) {
+ this.reference = reference;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof TargetNotAuditedEntity)) return false;
+
+ TargetNotAuditedEntity that = (TargetNotAuditedEntity) o;
+
+ if (data != null ? !data.equals(that.data) : that.data != null) return false;
+ if (id != null ? !id.equals(that.id) : that.id != null) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = (id != null ? id.hashCode() : 0);
+ result = 31 * result + (data != null ? data.hashCode() : 0);
+ return result;
+ }
+
+ public String toString() {
+ return "TargetNotAuditedEntity(id = " + id + ", data = " + data + ")";
+ }
+}
diff --git a/envers/src/test/java/org/hibernate/envers/test/integration/manytoone/unidirectional/RelationNotAuditedTarget.java b/envers/src/test/java/org/hibernate/envers/test/integration/manytoone/unidirectional/RelationNotAuditedTarget.java
new file mode 100644
index 0000000000..63a60df5c6
--- /dev/null
+++ b/envers/src/test/java/org/hibernate/envers/test/integration/manytoone/unidirectional/RelationNotAuditedTarget.java
@@ -0,0 +1,161 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.envers.test.integration.manytoone.unidirectional;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+
+import org.hibernate.ejb.Ejb3Configuration;
+import org.hibernate.envers.test.AbstractEntityTest;
+import org.hibernate.envers.test.entities.UnversionedStrTestEntity;
+import org.hibernate.envers.test.entities.manytoone.unidirectional.TargetNotAuditedEntity;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * @author Tomasz Bech
+ */
+public class RelationNotAuditedTarget extends AbstractEntityTest {
+ private Integer tnae1_id;
+ private Integer tnae2_id;
+
+ private Integer uste1_id;
+ private Integer uste2_id;
+
+ public void configure(Ejb3Configuration cfg) {
+ cfg.addAnnotatedClass(TargetNotAuditedEntity.class);
+ cfg.addAnnotatedClass(UnversionedStrTestEntity.class);
+ }
+
+ @BeforeClass(dependsOnMethods = "init")
+ public void initData() {
+ EntityManager em = getEntityManager();
+
+ UnversionedStrTestEntity uste1 = new UnversionedStrTestEntity("str1");
+ UnversionedStrTestEntity uste2 = new UnversionedStrTestEntity("str2");
+
+ // No revision
+ em.getTransaction().begin();
+
+ em.persist(uste1);
+ em.persist(uste2);
+
+ em.getTransaction().commit();
+
+ // Revision 1
+ em.getTransaction().begin();
+
+ uste1 = em.find(UnversionedStrTestEntity.class, uste1.getId());
+ uste2 = em.find(UnversionedStrTestEntity.class, uste2.getId());
+
+ TargetNotAuditedEntity tnae1 = new TargetNotAuditedEntity(1, "tnae1", uste1);
+ TargetNotAuditedEntity tnae2 = new TargetNotAuditedEntity(2, "tnae2", uste2);
+ em.persist(tnae1);
+ em.persist(tnae2);
+
+ em.getTransaction().commit();
+
+ // Revision 2
+ em.getTransaction().begin();
+
+ tnae1 = em.find(TargetNotAuditedEntity.class, tnae1.getId());
+ tnae2 = em.find(TargetNotAuditedEntity.class, tnae2.getId());
+
+ tnae1.setReference(uste2);
+ tnae2.setReference(uste1);
+
+ em.getTransaction().commit();
+
+ // Revision 3
+ em.getTransaction().begin();
+
+ tnae1 = em.find(TargetNotAuditedEntity.class, tnae1.getId());
+ tnae2 = em.find(TargetNotAuditedEntity.class, tnae2.getId());
+
+ //field not changed!!!
+ tnae1.setReference(uste2);
+ tnae2.setReference(uste2);
+
+ em.getTransaction().commit();
+
+ // Revision 4
+ em.getTransaction().begin();
+
+ tnae1 = em.find(TargetNotAuditedEntity.class, tnae1.getId());
+ tnae2 = em.find(TargetNotAuditedEntity.class, tnae2.getId());
+
+ tnae1.setReference(uste1);
+ tnae2.setReference(uste1);
+
+ em.getTransaction().commit();
+
+ //
+ tnae1_id = tnae1.getId();
+ tnae2_id = tnae2.getId();
+ uste1_id = uste1.getId();
+ uste2_id = uste2.getId();
+ }
+
+ @Test
+ public void testRevisionsCounts() {
+ List revisions = getAuditReader().getRevisions(TargetNotAuditedEntity.class, tnae1_id);
+ assert Arrays.asList(1, 2, 4).equals(revisions);
+ revisions = getAuditReader().getRevisions(TargetNotAuditedEntity.class, tnae2_id);
+ assert Arrays.asList(1, 2, 3, 4).equals(revisions);
+ }
+
+ @Test
+ public void testHistoryOfTnae1_id() {
+ UnversionedStrTestEntity uste1 = getEntityManager().find(UnversionedStrTestEntity.class, uste1_id);
+ UnversionedStrTestEntity uste2 = getEntityManager().find(UnversionedStrTestEntity.class, uste2_id);
+
+ TargetNotAuditedEntity rev1 = getAuditReader().find(TargetNotAuditedEntity.class, tnae1_id, 1);
+ TargetNotAuditedEntity rev2 = getAuditReader().find(TargetNotAuditedEntity.class, tnae1_id, 2);
+ TargetNotAuditedEntity rev3 = getAuditReader().find(TargetNotAuditedEntity.class, tnae1_id, 3);
+ TargetNotAuditedEntity rev4 = getAuditReader().find(TargetNotAuditedEntity.class, tnae1_id, 4);
+
+ assert rev1.getReference().equals(uste1);
+ assert rev2.getReference().equals(uste2);
+ assert rev3.getReference().equals(uste2);
+ assert rev4.getReference().equals(uste1);
+ }
+
+ @Test
+ public void testHistoryOfTnae2_id() {
+ UnversionedStrTestEntity uste1 = getEntityManager().find(UnversionedStrTestEntity.class, uste1_id);
+ UnversionedStrTestEntity uste2 = getEntityManager().find(UnversionedStrTestEntity.class, uste2_id);
+
+ TargetNotAuditedEntity rev1 = getAuditReader().find(TargetNotAuditedEntity.class, tnae2_id, 1);
+ TargetNotAuditedEntity rev2 = getAuditReader().find(TargetNotAuditedEntity.class, tnae2_id, 2);
+ TargetNotAuditedEntity rev3 = getAuditReader().find(TargetNotAuditedEntity.class, tnae2_id, 3);
+ TargetNotAuditedEntity rev4 = getAuditReader().find(TargetNotAuditedEntity.class, tnae2_id, 4);
+
+ assert rev1.getReference().equals(uste2);
+ assert rev2.getReference().equals(uste1);
+ assert rev3.getReference().equals(uste2);
+ assert rev4.getReference().equals(uste1);
+ }
+}