1414 */
1515package org .grails .datastore .gorm .events ;
1616
17+ import java .lang .reflect .Field ;
1718import java .util .*;
1819import java .util .concurrent .ConcurrentHashMap ;
1920import java .util .concurrent .ConcurrentLinkedQueue ;
2021
22+ import grails .gorm .annotation .AutoTimestamp ;
2123import org .grails .datastore .gorm .timestamp .DefaultTimestampProvider ;
2224import org .grails .datastore .gorm .timestamp .TimestampProvider ;
2325import org .grails .datastore .mapping .config .Entity ;
@@ -45,13 +47,11 @@ public class AutoTimestampEventListener extends AbstractPersistenceEventListener
4547 public static final String DATE_CREATED_PROPERTY = "dateCreated" ;
4648 public static final String LAST_UPDATED_PROPERTY = "lastUpdated" ;
4749
48- protected Map <String , String > entitiesWithDateCreated = new ConcurrentHashMap <>();
49- protected Map <String , String > entitiesWithLastUpdated = new ConcurrentHashMap <>();
50+ protected Map <String , Set < String > > entitiesWithDateCreated = new ConcurrentHashMap <>();
51+ protected Map <String , Set < String > > entitiesWithLastUpdated = new ConcurrentHashMap <>();
5052 protected Collection <String > uninitializedEntities = new ConcurrentLinkedQueue <>();
51-
52-
53+
5354 private TimestampProvider timestampProvider = new DefaultTimestampProvider ();
54-
5555
5656 public AutoTimestampEventListener (final Datastore datastore ) {
5757 super (datastore );
@@ -95,19 +95,23 @@ public boolean beforeInsert(PersistentEntity entity, EntityAccess ea) {
9595 initializeIfNecessary (entity , name );
9696 Class <?> dateCreatedType = null ;
9797 Object timestamp = null ;
98- String prop = getDateCreatedPropertyName (name );
99- if (prop != null ) {
100- dateCreatedType = ea .getPropertyType (prop );
101- timestamp = timestampProvider .createTimestamp (dateCreatedType );
102- ea .setProperty (prop , timestamp );
98+ Set <String > props = getDateCreatedPropertyNames (name );
99+ if (props != null ) {
100+ for (String prop : props ) {
101+ dateCreatedType = ea .getPropertyType (prop );
102+ timestamp = timestampProvider .createTimestamp (dateCreatedType );
103+ ea .setProperty (prop , timestamp );
104+ }
103105 }
104- prop = getLastUpdatedPropertyName (name );
105- if (prop != null ) {
106- Class <?> lastUpdateType = ea .getPropertyType (prop );
107- if (dateCreatedType == null || !lastUpdateType .isAssignableFrom (dateCreatedType )) {
108- timestamp = timestampProvider .createTimestamp (lastUpdateType );
106+ props = getLastUpdatedPropertyNames (name );
107+ if (props != null ) {
108+ for (String prop : props ) {
109+ Class <?> lastUpdateType = ea .getPropertyType (prop );
110+ if (dateCreatedType == null || !lastUpdateType .isAssignableFrom (dateCreatedType )) {
111+ timestamp = timestampProvider .createTimestamp (lastUpdateType );
112+ }
113+ ea .setProperty (prop , timestamp );
109114 }
110- ea .setProperty (prop , timestamp );
111115 }
112116 return true ;
113117 }
@@ -120,43 +124,70 @@ private void initializeIfNecessary(PersistentEntity entity, String name) {
120124 }
121125
122126 public boolean beforeUpdate (PersistentEntity entity , EntityAccess ea ) {
123- String prop = getLastUpdatedPropertyName (entity .getName ());
124- if (prop != null ) {
125- Class <?> lastUpdateType = ea .getPropertyType (prop );
126- Object timestamp = timestampProvider .createTimestamp (lastUpdateType );
127- ea .setProperty (prop , timestamp );
127+ Set <String > props = getLastUpdatedPropertyNames (entity .getName ());
128+ if (props != null ) {
129+ for (String prop : props ) {
130+ Class <?> lastUpdateType = ea .getPropertyType (prop );
131+ Object timestamp = timestampProvider .createTimestamp (lastUpdateType );
132+ ea .setProperty (prop , timestamp );
133+ }
128134 }
129135 return true ;
130136 }
131137
132- protected String getLastUpdatedPropertyName (String n ) {
133- return entitiesWithLastUpdated .get (n );
138+ protected Set < String > getLastUpdatedPropertyNames (String entityName ) {
139+ return entitiesWithLastUpdated .get (entityName );
134140 }
135141
136- protected String getDateCreatedPropertyName (String n ) {
137- return entitiesWithDateCreated .get (n );
142+ protected Set <String > getDateCreatedPropertyNames (String entityName ) {
143+ return entitiesWithDateCreated .get (entityName );
144+ }
145+
146+ private static Field getFieldFromHierarchy (PersistentEntity persistentEntity , String fieldName ) {
147+ Class <?> clazz = persistentEntity .getJavaClass ();
148+ while (clazz != null ) {
149+ try {
150+ return clazz .getDeclaredField (fieldName );
151+ } catch (NoSuchFieldException e ) {
152+ persistentEntity = persistentEntity .getParentEntity ();
153+ clazz = persistentEntity == null ? null : persistentEntity .getJavaClass ();
154+ }
155+ }
156+ return null ;
138157 }
139158
140159 protected void storeDateCreatedAndLastUpdatedInfo (PersistentEntity persistentEntity ) {
141160 if (persistentEntity .isInitialized ()) {
142161 ClassMapping <?> classMapping = persistentEntity .getMapping ();
143- Entity mappedForm = classMapping .getMappedForm ();
162+ Entity <?> mappedForm = classMapping .getMappedForm ();
144163 if (mappedForm == null || mappedForm .isAutoTimestamp ()) {
145- storeTimestampAvailability (entitiesWithDateCreated , persistentEntity ,
146- persistentEntity .getPropertyByName (mappedForm .getDateCreated () != null ?
147- mappedForm .getDateCreated () : DATE_CREATED_PROPERTY ));
148- storeTimestampAvailability (entitiesWithLastUpdated , persistentEntity ,
149- persistentEntity .getPropertyByName (mappedForm .getLastUpdated () != null ?
150- mappedForm .getLastUpdated () : LAST_UPDATED_PROPERTY ));
164+ for (PersistentProperty <?> property : persistentEntity .getPersistentProperties ()) {
165+ if (property .getName ().equals (LAST_UPDATED_PROPERTY )) {
166+ storeTimestampAvailability (entitiesWithLastUpdated , persistentEntity , property );
167+ } else if (property .getName ().equals (DATE_CREATED_PROPERTY )) {
168+ storeTimestampAvailability (entitiesWithDateCreated , persistentEntity , property );
169+ } else {
170+ Field field = getFieldFromHierarchy (persistentEntity , property .getName ());
171+ if (field != null && field .isAnnotationPresent (AutoTimestamp .class )) {
172+ AutoTimestamp autoTimestamp = field .getAnnotation (AutoTimestamp .class );
173+ if (autoTimestamp .value ()) {
174+ storeTimestampAvailability (entitiesWithLastUpdated , persistentEntity , property );
175+ } else {
176+ storeTimestampAvailability (entitiesWithDateCreated , persistentEntity , property );
177+ }
178+ }
179+ }
180+ }
151181 }
152182 } else {
153183 uninitializedEntities .add (persistentEntity .getName ());
154184 }
155185 }
156186
157- protected void storeTimestampAvailability (Map <String , String > timestampAvailabilityMap , PersistentEntity persistentEntity , PersistentProperty <?> property ) {
187+ protected void storeTimestampAvailability (Map <String , Set < String > > timestampAvailabilityMap , PersistentEntity persistentEntity , PersistentProperty <?> property ) {
158188 if (property != null && timestampProvider .supportsCreating (property .getType ())) {
159- timestampAvailabilityMap .put (persistentEntity .getName (), property .getName ());
189+ Set <String > timestampProperties = timestampAvailabilityMap .computeIfAbsent (persistentEntity .getName (), k -> new HashSet <>());
190+ timestampProperties .add (property .getName ());
160191 }
161192 }
162193
@@ -172,25 +203,25 @@ public void setTimestampProvider(TimestampProvider timestampProvider) {
172203 this .timestampProvider = timestampProvider ;
173204 }
174205
175- private void processAllEntries (final Set <Map .Entry <String , String >> entries , final Runnable runnable ) {
176- Map <String , String > originalValues = new LinkedHashMap <>();
177- for (Map .Entry <String , String > entry : entries ) {
206+ private void processAllEntries (final Set <Map .Entry <String , Set < String > >> entries , final Runnable runnable ) {
207+ Map <String , Set < String > > originalValues = new LinkedHashMap <>();
208+ for (Map .Entry <String , Set < String > > entry : entries ) {
178209 originalValues .put (entry .getKey (), entry .getValue ());
179210 entry .setValue (null );
180211 }
181212 runnable .run ();
182- for (Map .Entry <String , String > entry : entries ) {
213+ for (Map .Entry <String , Set < String > > entry : entries ) {
183214 entry .setValue (originalValues .get (entry .getKey ()));
184215 }
185216 }
186217
187- private void processEntries (final List <Class > classes , Map <String , String > entities , final Runnable runnable ) {
188- Set <Map .Entry <String , String >> entries = new HashSet <>();
218+ private void processEntries (final List <Class > classes , Map <String , Set < String > > entities , final Runnable runnable ) {
219+ Set <Map .Entry <String , Set < String > >> entries = new HashSet <>();
189220 final List <String > classNames = new ArrayList <>(classes .size ());
190221 for (Class clazz : classes ) {
191222 classNames .add (clazz .getName ());
192223 }
193- for (Map .Entry <String , String > entry : entities .entrySet ()) {
224+ for (Map .Entry <String , Set < String > > entry : entities .entrySet ()) {
194225 if (classNames .contains (entry .getKey ())) {
195226 entries .add (entry );
196227 }
0 commit comments