You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@deltaspike.apache.org by Nico Schlebusch <ni...@gmail.com> on 2016/12/07 10:22:26 UTC

DeltaSpike Data - Custom PrePersistAuditListener and PreUpdateAuditListener

Good day,

I'm using the @EntityListeners(AuditEntityListener.class) and 
@CreatedOn, @ModifiedOn and @ModifiedBy annotations on an Entity bean 
with the difference that I have a custom implementation of 
java.time.ChronoLocalDateTime which converts any LocalDateTime + 
ZoneOffset OR a ZonedDateTime to be the UTC date & time.

    public class UTCDateTime implements ChronoLocalDateTime<LocalDate>,
    Serializable {

       private static final long serialVersionUID = 6492792765662073566L;
       private static final ZoneOffset UTC = ZoneOffset.UTC;
       private final LocalDateTime datetime;

       // a lot of other details left out
    }

The entity bean parts

    @MappedSuperclass
    public class InsertableAuditableBean extends BaseBean implements
    InsertableAuditable {

       @NotNull
       @Size(min = 1, max = 50)
       @Column(name = "zz_inserted_by", length = 50, nullable = false)
       private String insertedBy;

    @CreatedOn
       @NotNull
       @Temporal(value = TemporalType.TIMESTAMP)
       @Column(name = "zz_inserted_on", nullable = false)
       private UTCDateTime insertedOn;

       // getters & setters
    }

    @MappedSuperclass
    public class UpdateableAuditableBean extends InsertableAuditableBean
    implements UpdateableAuditable {

    @ModifiedBy
       @Size(min = 1, max = 50)
       @Column(name = "zz_updated_by", length = 50, nullable = true)
       private String updatedBy;

    @ModifiedOn
       @Temporal(value = TemporalType.TIMESTAMP)
       @Column(name = "zz_updated_on", nullable = true)
       private UTCDateTime updatedOn;

       // getters & setters
    }

    @Entity
    @EntityListeners(AuditEntityListener.class)
    @Table(schema = "data", name = "manufacturer", uniqueConstraints = {
         @UniqueConstraint(columnNames = { "man_name", "man_country" })
    })
    @AttributeOverrides({
         @AttributeOverride(name = "primaryKey", column = @Column(name =
    "man_serial")),
         @AttributeOverride(name = "insertedBy", column = @Column(name =
    "man_inserted_by")),
         @AttributeOverride(name = "insertedOn", column = @Column(name =
    "man_inserted_on")),
         @AttributeOverride(name = "updatedBy", column = @Column(name =
    "man_updated_by")),
         @AttributeOverride(name = "updatedOn", column = @Column(name =
    "man_updated_on"))
    })
    @SequenceGenerator(name = "default_seq", schema = "data",
    sequenceName = "manufacturer_man_serial_seq",
         allocationSize = 1)
    public class Manufacturer extends MirroredUpdateableAuditableBean
    implements IManufacturer {
       // nothing special here
    }

There is also a custom AttributeConverter for the UTCDateTime class 
because the epoch value is saved in the database.

    @Converter(autoApply = true)
    public class UTCDateTimePersistenceConverter implements
    AttributeConverter<UTCDateTime, Long> {

       @Override
       public Long convertToDatabaseColumn(final UTCDateTime entityValue) {
         Long res = null;
         if (entityValue != null) {
           res = entityValue.toMillis();
         }
         return res;
       }

       @Override
       public UTCDateTime convertToEntityAttribute(final Long
    databaseValue) {
         UTCDateTime res = null;
         if (databaseValue != null) {
           res = new UTCDateTime(Instant.ofEpochMilli(databaseValue));
         }
         return res;
       }
    }

Now when I persist the entity I get the following exception (the last 
bit with the real cause):

    Caused by: org.apache.deltaspike.data.api.QueryInvocationException:
    Failed calling Repository:
    [Repository=systems.apace.data.manufacturer.model.dao.ManufacturerDAO,entity=systems.apace.data.manufacturer.model.Manufacturer,method=persist,exception=class
    java.lang.reflect.InvocationTargetException,message=null
             at
    systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
    Caused by: java.lang.reflect.InvocationTargetException
             at
    systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
    Caused by:
    org.apache.deltaspike.data.impl.audit.AuditPropertyException: Failed
    to set property Manufacturer.insertedOn, is this a temporal type?
             at
    systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
    Caused by: java.lang.IllegalArgumentException: Annotated field is
    not a date class: class za.co.t9.common.utils.time.UTCDateTime
             at
    systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)

Is there a way to implement my own 
org.apache.deltaspike.data.impl.audit.PrePersistAuditListener and 
org.apache.deltaspike.data.impl.audit.PreUpdateAuditListener and use 
them to create the instance of UTCDateTime?

Would it be correct to write my own EntityListener --> 
UTCDateTimeAuditListener and use it 
@EntityListeners(UTCDateTimeAuditEntityListener.class) where 
UTCDateTimeAuditListener follows the 
org.apache.deltaspike.data.impl.audit.AuditEntityListener approach?
Secondly, do I need to use a CDI Qualifier somewhere to make sure that 
my UTCDateTimeAuditEntityListener gets a reference to the correct 
PrePersistAuditListener and PreUpdateAuditListener that knows how to 
construct the UTCDateTime instance?

Lastly, I don't know if it is relevant, but where does 
org.apache.deltaspike.data.impl.audit.TimestampsProvider fit into this 
scenario?

Thank you for your time

Kind regards,
Nico Schlebusch
nicoschl@gmail.com <ma...@gmail.com>



Re: DeltaSpike Data - Custom PrePersistAuditListener and PreUpdateAuditListener

Posted by Nico Schlebusch <ni...@gmail.com>.
Hi John,

Issue raised - https://issues.apache.org/jira/browse/DELTASPIKE-1229

Kind regards,
Nico Schlebusch
nicoschl@gmail.com <ma...@gmail.com>


On 20/12/2016 23:13, Nico Schlebusch wrote:
> No problem, thanks for your help. I'll raise the issue in JIRA.
>
> Kind regards,
> Nico Schlebusch
> nicoschl@gmail.com <ma...@gmail.com>
>
>
> On 20/12/2016 23:11, John D. Ament wrote:
>> Gah shoot, sorry about that.  It won't work because its a package private
>> class, and the classloader will block it.
>>
>> I'll get something in to fix this, unfortunately it won't work until my
>> change is in.  Please do make sure to raise an issue in JIRA so I don't
>> lose track.  Thanks for checking it out.
>>
>> John
>>
>> On Tue, Dec 20, 2016 at 4:07 PM Nico Schlebusch<ni...@gmail.com>  wrote:
>>
>>> Hi John,
>>>
>>> Thanks for the suggestion on vetoing the TimestampsProvider, but there is
>>> a new problem with my approach or lack of understanding of Portable
>>> Extensions.
>>>
>>> I first created the portable extension inside my own package structure,
>>> but then the compiler fails to resolve TimestampsProvider because it is a
>>> package protected class. I then moved my extension into the same package
>>> (org.apache.deltaspike.data.impl.audit) as TimestampsProvider but then got
>>> this exception on deployment
>>>
>>> Caused by: java.lang.IllegalAccessError: tried to access class
>>> org.apache.deltaspike.data.impl.audit.PrincipalProvider from class
>>> org.apache.deltaspike.data.impl.audit.VetoDeltaSpikeAuditProvidersExtension
>>>          at
>>> org.apache.deltaspike.data.impl.audit.VetoDeltaSpikeAuditProvidersExtension.rejectPrincipalProvider(VetoDeltaSpikeAuditProvidersExtension.java:43)
>>>          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>>>          at
>>> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
>>>          at
>>> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>>>          at java.lang.reflect.Method.invoke(Method.java:498)
>>>          at
>>> org.jboss.weld.injection.StaticMethodInjectionPoint.invoke(StaticMethodInjectionPoint.java:88)
>>>
>>> I read somewhere that happens when the classes aren't loaded with the same
>>> classloader.
>>>
>>> Any other ideas on how to veto the TimestampsProvider?
>>>
>>>
>>> Kind regards,
>>> Nico Schlebusch
>>> nicoschl@gmail.com
>>>
>>>
>>> On 20/12/2016 17:23, John D. Ament wrote:
>>>
>>> Ok, that makes sense.  I wanted to verify your behavior, which means
>>> alternative makes no sense here.
>>>
>>> So with that said, what I'm thinking is that you can forcibly veto the
>>> class in a portable extension to disable its execution.  It would be as
>>> simple as
>>>
>>>      public void rejectDefaultClass(@Observes
>>> ProcessAnnotatedType<TimestampsProvider> pat) {
>>>          pat.veto();
>>>      }
>>>
>>>
>>> John
>>>
>>> On Tue, Dec 20, 2016 at 9:54 AM Nico Schlebusch<ni...@gmail.com>
>>> wrote:
>>>
>>> John,
>>>
>>> That loop executes the number of times there are implementations of the
>>> PrePersistAuditListener. When I have my own implementation deployed it
>>> executes 3 times. The PrincipalProvider, my custom implementation
>>> (UTCDateTimeAuditProvider) and then TimestampsProvider are executed in
>>> that order.
>>>
>>> Kind regards,
>>> Nico Schlebusch
>>> nicoschl@gmail.com  <ma...@gmail.com>
>>>
>>>
>>> On 20/12/2016 16:33, John D. Ament wrote:
>>>> Nico,
>>>>
>>>> There's a for loop here
>>>>
>>> https://github.com/apache/deltaspike/blob/master/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/audit/AuditEntityListener.java#L38
>>>> How many times does this for loop execute?
>>>>
>>>> John
>>>>
>>>> On Tue, Dec 20, 2016 at 9:23 AM Nico Schlebusch<ni...@gmail.com>
>>> wrote:
>>>>> Hi John,
>>>>>
>>>>> Thanks for the answer.
>>>>>
>>>>> The AuditEntityListener is called once from my debugging sessions.
>>>>>
>>>>> I'll definitely raise a feature request, it might just not be in the
>>> next
>>>>> 2 weeks. Would the feature request be to take @Alternative beans into
>>>>> considerations when looking up the beans that implements the 2
>>> interfaces,
>>>>> PrePersistAuditListener & PreUpdateAuditListener? Meaning that lines
>>> 40-41
>>>>> and 53-54 from the link below, need to filter out the @Default beans
>>> when
>>>>> an @Alternative is available? Or should I phrase it differently?
>>>>>
>>>>> Kind regards,
>>>>> Nico Schlebusch
>>>>> nicoschl@gmail.com
>>>>>
>>>>>
>>>>> On 20/12/2016 15:56, John D. Ament wrote:
>>>>>
>>>>> Nico,
>>>>>
>>>>> Seems the logic in DeltaSpike is to loop through the beans.  Can you
>>> check
>>>>> if you're seeing this loop is called multiple times?
>>>>>
>>> https://github.com/apache/deltaspike/blob/master/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/audit/AuditEntityListener.java
>>>>> Anyways, would be good to have this support direct in deltaspike.  Mind
>>>>> raising a feature request?
>>>>> https://issues.apache.org/jira/browse/DELTASPIKE
>>>>>
>>>>> John
>>>>>
>
>



Re: DeltaSpike Data - Custom PrePersistAuditListener and PreUpdateAuditListener

Posted by Nico Schlebusch <ni...@gmail.com>.
No problem, thanks for your help. I'll raise the issue in JIRA.

Kind regards,
Nico Schlebusch
nicoschl@gmail.com <ma...@gmail.com>


On 20/12/2016 23:11, John D. Ament wrote:
> Gah shoot, sorry about that.  It won't work because its a package private
> class, and the classloader will block it.
>
> I'll get something in to fix this, unfortunately it won't work until my
> change is in.  Please do make sure to raise an issue in JIRA so I don't
> lose track.  Thanks for checking it out.
>
> John
>
> On Tue, Dec 20, 2016 at 4:07 PM Nico Schlebusch <ni...@gmail.com> wrote:
>
>> Hi John,
>>
>> Thanks for the suggestion on vetoing the TimestampsProvider, but there is
>> a new problem with my approach or lack of understanding of Portable
>> Extensions.
>>
>> I first created the portable extension inside my own package structure,
>> but then the compiler fails to resolve TimestampsProvider because it is a
>> package protected class. I then moved my extension into the same package
>> (org.apache.deltaspike.data.impl.audit) as TimestampsProvider but then got
>> this exception on deployment
>>
>> Caused by: java.lang.IllegalAccessError: tried to access class
>> org.apache.deltaspike.data.impl.audit.PrincipalProvider from class
>> org.apache.deltaspike.data.impl.audit.VetoDeltaSpikeAuditProvidersExtension
>>          at
>> org.apache.deltaspike.data.impl.audit.VetoDeltaSpikeAuditProvidersExtension.rejectPrincipalProvider(VetoDeltaSpikeAuditProvidersExtension.java:43)
>>          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>>          at
>> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
>>          at
>> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>>          at java.lang.reflect.Method.invoke(Method.java:498)
>>          at
>> org.jboss.weld.injection.StaticMethodInjectionPoint.invoke(StaticMethodInjectionPoint.java:88)
>>
>> I read somewhere that happens when the classes aren't loaded with the same
>> classloader.
>>
>> Any other ideas on how to veto the TimestampsProvider?
>>
>>
>> Kind regards,
>> Nico Schlebusch
>> nicoschl@gmail.com
>>
>>
>> On 20/12/2016 17:23, John D. Ament wrote:
>>
>> Ok, that makes sense.  I wanted to verify your behavior, which means
>> alternative makes no sense here.
>>
>> So with that said, what I'm thinking is that you can forcibly veto the
>> class in a portable extension to disable its execution.  It would be as
>> simple as
>>
>>      public void rejectDefaultClass(@Observes
>> ProcessAnnotatedType<TimestampsProvider> pat) {
>>          pat.veto();
>>      }
>>
>>
>> John
>>
>> On Tue, Dec 20, 2016 at 9:54 AM Nico Schlebusch <ni...@gmail.com>
>> wrote:
>>
>> John,
>>
>> That loop executes the number of times there are implementations of the
>> PrePersistAuditListener. When I have my own implementation deployed it
>> executes 3 times. The PrincipalProvider, my custom implementation
>> (UTCDateTimeAuditProvider) and then TimestampsProvider are executed in
>> that order.
>>
>> Kind regards,
>> Nico Schlebusch
>> nicoschl@gmail.com <ma...@gmail.com>
>>
>>
>> On 20/12/2016 16:33, John D. Ament wrote:
>>> Nico,
>>>
>>> There's a for loop here
>>>
>> https://github.com/apache/deltaspike/blob/master/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/audit/AuditEntityListener.java#L38
>>> How many times does this for loop execute?
>>>
>>> John
>>>
>>> On Tue, Dec 20, 2016 at 9:23 AM Nico Schlebusch <ni...@gmail.com>
>> wrote:
>>>> Hi John,
>>>>
>>>> Thanks for the answer.
>>>>
>>>> The AuditEntityListener is called once from my debugging sessions.
>>>>
>>>> I'll definitely raise a feature request, it might just not be in the
>> next
>>>> 2 weeks. Would the feature request be to take @Alternative beans into
>>>> considerations when looking up the beans that implements the 2
>> interfaces,
>>>> PrePersistAuditListener & PreUpdateAuditListener? Meaning that lines
>> 40-41
>>>> and 53-54 from the link below, need to filter out the @Default beans
>> when
>>>> an @Alternative is available? Or should I phrase it differently?
>>>>
>>>> Kind regards,
>>>> Nico Schlebusch
>>>> nicoschl@gmail.com
>>>>
>>>>
>>>> On 20/12/2016 15:56, John D. Ament wrote:
>>>>
>>>> Nico,
>>>>
>>>> Seems the logic in DeltaSpike is to loop through the beans.  Can you
>> check
>>>> if you're seeing this loop is called multiple times?
>>>>
>> https://github.com/apache/deltaspike/blob/master/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/audit/AuditEntityListener.java
>>>> Anyways, would be good to have this support direct in deltaspike.  Mind
>>>> raising a feature request?
>>>> https://issues.apache.org/jira/browse/DELTASPIKE
>>>>
>>>> John
>>>>
>>



Re: DeltaSpike Data - Custom PrePersistAuditListener and PreUpdateAuditListener

Posted by "John D. Ament" <jo...@apache.org>.
Gah shoot, sorry about that.  It won't work because its a package private
class, and the classloader will block it.

I'll get something in to fix this, unfortunately it won't work until my
change is in.  Please do make sure to raise an issue in JIRA so I don't
lose track.  Thanks for checking it out.

John

On Tue, Dec 20, 2016 at 4:07 PM Nico Schlebusch <ni...@gmail.com> wrote:

> Hi John,
>
> Thanks for the suggestion on vetoing the TimestampsProvider, but there is
> a new problem with my approach or lack of understanding of Portable
> Extensions.
>
> I first created the portable extension inside my own package structure,
> but then the compiler fails to resolve TimestampsProvider because it is a
> package protected class. I then moved my extension into the same package
> (org.apache.deltaspike.data.impl.audit) as TimestampsProvider but then got
> this exception on deployment
>
> Caused by: java.lang.IllegalAccessError: tried to access class
> org.apache.deltaspike.data.impl.audit.PrincipalProvider from class
> org.apache.deltaspike.data.impl.audit.VetoDeltaSpikeAuditProvidersExtension
>         at
> org.apache.deltaspike.data.impl.audit.VetoDeltaSpikeAuditProvidersExtension.rejectPrincipalProvider(VetoDeltaSpikeAuditProvidersExtension.java:43)
>         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>         at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
>         at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>         at java.lang.reflect.Method.invoke(Method.java:498)
>         at
> org.jboss.weld.injection.StaticMethodInjectionPoint.invoke(StaticMethodInjectionPoint.java:88)
>
> I read somewhere that happens when the classes aren't loaded with the same
> classloader.
>
> Any other ideas on how to veto the TimestampsProvider?
>
>
> Kind regards,
> Nico Schlebusch
> nicoschl@gmail.com
>
>
> On 20/12/2016 17:23, John D. Ament wrote:
>
> Ok, that makes sense.  I wanted to verify your behavior, which means
> alternative makes no sense here.
>
> So with that said, what I'm thinking is that you can forcibly veto the
> class in a portable extension to disable its execution.  It would be as
> simple as
>
>     public void rejectDefaultClass(@Observes
> ProcessAnnotatedType<TimestampsProvider> pat) {
>         pat.veto();
>     }
>
>
> John
>
> On Tue, Dec 20, 2016 at 9:54 AM Nico Schlebusch <ni...@gmail.com>
> wrote:
>
> John,
>
> That loop executes the number of times there are implementations of the
> PrePersistAuditListener. When I have my own implementation deployed it
> executes 3 times. The PrincipalProvider, my custom implementation
> (UTCDateTimeAuditProvider) and then TimestampsProvider are executed in
> that order.
>
> Kind regards,
> Nico Schlebusch
> nicoschl@gmail.com <ma...@gmail.com>
>
>
> On 20/12/2016 16:33, John D. Ament wrote:
> > Nico,
> >
> > There's a for loop here
> >
> https://github.com/apache/deltaspike/blob/master/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/audit/AuditEntityListener.java#L38
> >
> > How many times does this for loop execute?
> >
> > John
> >
> > On Tue, Dec 20, 2016 at 9:23 AM Nico Schlebusch <ni...@gmail.com>
> wrote:
> >
> >> Hi John,
> >>
> >> Thanks for the answer.
> >>
> >> The AuditEntityListener is called once from my debugging sessions.
> >>
> >> I'll definitely raise a feature request, it might just not be in the
> next
> >> 2 weeks. Would the feature request be to take @Alternative beans into
> >> considerations when looking up the beans that implements the 2
> interfaces,
> >> PrePersistAuditListener & PreUpdateAuditListener? Meaning that lines
> 40-41
> >> and 53-54 from the link below, need to filter out the @Default beans
> when
> >> an @Alternative is available? Or should I phrase it differently?
> >>
> >> Kind regards,
> >> Nico Schlebusch
> >> nicoschl@gmail.com
> >>
> >>
> >> On 20/12/2016 15:56, John D. Ament wrote:
> >>
> >> Nico,
> >>
> >> Seems the logic in DeltaSpike is to loop through the beans.  Can you
> check
> >> if you're seeing this loop is called multiple times?
> >>
> https://github.com/apache/deltaspike/blob/master/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/audit/AuditEntityListener.java
> >>
> >> Anyways, would be good to have this support direct in deltaspike.  Mind
> >> raising a feature request?
> >> https://issues.apache.org/jira/browse/DELTASPIKE
> >>
> >> John
> >>
>
>
>

Re: DeltaSpike Data - Custom PrePersistAuditListener and PreUpdateAuditListener

Posted by Nico Schlebusch <ni...@gmail.com>.
Hi John,

Thanks for the suggestion on vetoing the TimestampsProvider, but there 
is a new problem with my approach or lack of understanding of Portable 
Extensions.

I first created the portable extension inside my own package structure, 
but then the compiler fails to resolve TimestampsProvider because it is 
a package protected class. I then moved my extension into the same 
package (org.apache.deltaspike.data.impl.audit) as TimestampsProvider 
but then got this exception on deployment

Caused by: java.lang.IllegalAccessError: tried to access class 
org.apache.deltaspike.data.impl.audit.PrincipalProvider from class 
org.apache.deltaspike.data.impl.audit.VetoDeltaSpikeAuditProvidersExtension
         at 
org.apache.deltaspike.data.impl.audit.VetoDeltaSpikeAuditProvidersExtension.rejectPrincipalProvider(VetoDeltaSpikeAuditProvidersExtension.java:43)
         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
         at 
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
         at 
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
         at java.lang.reflect.Method.invoke(Method.java:498)
         at 
org.jboss.weld.injection.StaticMethodInjectionPoint.invoke(StaticMethodInjectionPoint.java:88)

I read somewhere that happens when the classes aren't loaded with the 
same classloader.

Any other ideas on how to veto the TimestampsProvider?

Kind regards,
Nico Schlebusch
nicoschl@gmail.com <ma...@gmail.com>


On 20/12/2016 17:23, John D. Ament wrote:
> Ok, that makes sense.  I wanted to verify your behavior, which means 
> alternative makes no sense here.
>
> So with that said, what I'm thinking is that you can forcibly veto the 
> class in a portable extension to disable its execution.  It would be 
> as simple as
>
>     public void rejectDefaultClass(@Observes 
> ProcessAnnotatedType<TimestampsProvider> pat) {
>         pat.veto();
>     }
>
>
> John
>
> On Tue, Dec 20, 2016 at 9:54 AM Nico Schlebusch <nicoschl@gmail.com 
> <ma...@gmail.com>> wrote:
>
>     John,
>
>     That loop executes the number of times there are implementations
>     of the
>     PrePersistAuditListener. When I have my own implementation deployed it
>     executes 3 times. The PrincipalProvider, my custom implementation
>     (UTCDateTimeAuditProvider) and then TimestampsProvider are executed in
>     that order.
>
>     Kind regards,
>     Nico Schlebusch
>     nicoschl@gmail.com <ma...@gmail.com>
>     <mailto:nicoschl@gmail.com <ma...@gmail.com>>
>
>
>     On 20/12/2016 16:33, John D. Ament wrote:
>     > Nico,
>     >
>     > There's a for loop here
>     >
>     https://github.com/apache/deltaspike/blob/master/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/audit/AuditEntityListener.java#L38
>     >
>     > How many times does this for loop execute?
>     >
>     > John
>     >
>     > On Tue, Dec 20, 2016 at 9:23 AM Nico Schlebusch
>     <nicoschl@gmail.com <ma...@gmail.com>> wrote:
>     >
>     >> Hi John,
>     >>
>     >> Thanks for the answer.
>     >>
>     >> The AuditEntityListener is called once from my debugging sessions.
>     >>
>     >> I'll definitely raise a feature request, it might just not be
>     in the next
>     >> 2 weeks. Would the feature request be to take @Alternative
>     beans into
>     >> considerations when looking up the beans that implements the 2
>     interfaces,
>     >> PrePersistAuditListener & PreUpdateAuditListener? Meaning that
>     lines 40-41
>     >> and 53-54 from the link below, need to filter out the @Default
>     beans when
>     >> an @Alternative is available? Or should I phrase it differently?
>     >>
>     >> Kind regards,
>     >> Nico Schlebusch
>     >> nicoschl@gmail.com <ma...@gmail.com>
>     >>
>     >>
>     >> On 20/12/2016 15:56, John D. Ament wrote:
>     >>
>     >> Nico,
>     >>
>     >> Seems the logic in DeltaSpike is to loop through the beans. 
>     Can you check
>     >> if you're seeing this loop is called multiple times?
>     >>
>     https://github.com/apache/deltaspike/blob/master/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/audit/AuditEntityListener.java
>     >>
>     >> Anyways, would be good to have this support direct in
>     deltaspike.  Mind
>     >> raising a feature request?
>     >> https://issues.apache.org/jira/browse/DELTASPIKE
>     >>
>     >> John
>     >>
>


Re: DeltaSpike Data - Custom PrePersistAuditListener and PreUpdateAuditListener

Posted by "John D. Ament" <jo...@apache.org>.
Ok, that makes sense.  I wanted to verify your behavior, which means
alternative makes no sense here.

So with that said, what I'm thinking is that you can forcibly veto the
class in a portable extension to disable its execution.  It would be as
simple as

    public void rejectDefaultClass(@Observes
ProcessAnnotatedType<TimestampsProvider> pat) {
        pat.veto();
    }


John

On Tue, Dec 20, 2016 at 9:54 AM Nico Schlebusch <ni...@gmail.com> wrote:

> John,
>
> That loop executes the number of times there are implementations of the
> PrePersistAuditListener. When I have my own implementation deployed it
> executes 3 times. The PrincipalProvider, my custom implementation
> (UTCDateTimeAuditProvider) and then TimestampsProvider are executed in
> that order.
>
> Kind regards,
> Nico Schlebusch
> nicoschl@gmail.com <ma...@gmail.com>
>
>
> On 20/12/2016 16:33, John D. Ament wrote:
> > Nico,
> >
> > There's a for loop here
> >
> https://github.com/apache/deltaspike/blob/master/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/audit/AuditEntityListener.java#L38
> >
> > How many times does this for loop execute?
> >
> > John
> >
> > On Tue, Dec 20, 2016 at 9:23 AM Nico Schlebusch <ni...@gmail.com>
> wrote:
> >
> >> Hi John,
> >>
> >> Thanks for the answer.
> >>
> >> The AuditEntityListener is called once from my debugging sessions.
> >>
> >> I'll definitely raise a feature request, it might just not be in the
> next
> >> 2 weeks. Would the feature request be to take @Alternative beans into
> >> considerations when looking up the beans that implements the 2
> interfaces,
> >> PrePersistAuditListener & PreUpdateAuditListener? Meaning that lines
> 40-41
> >> and 53-54 from the link below, need to filter out the @Default beans
> when
> >> an @Alternative is available? Or should I phrase it differently?
> >>
> >> Kind regards,
> >> Nico Schlebusch
> >> nicoschl@gmail.com
> >>
> >>
> >> On 20/12/2016 15:56, John D. Ament wrote:
> >>
> >> Nico,
> >>
> >> Seems the logic in DeltaSpike is to loop through the beans.  Can you
> check
> >> if you're seeing this loop is called multiple times?
> >>
> https://github.com/apache/deltaspike/blob/master/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/audit/AuditEntityListener.java
> >>
> >> Anyways, would be good to have this support direct in deltaspike.  Mind
> >> raising a feature request?
> >> https://issues.apache.org/jira/browse/DELTASPIKE
> >>
> >> John
> >>
> >> On Tue, Dec 13, 2016 at 2:58 AM Nico Schlebusch <ni...@gmail.com>
> >> wrote:
> >>
> >> Good day,
> >>
> >> I have made some progress in answering my question, but I'm facing a new
> >> problem. Please see the updated Q on SO -
> >>
> >>
> http://stackoverflow.com/questions/41057116/deltaspike-data-cdi-jpa-custom-prepersistauditlistener-and-preupdateauditlis
> >>
> >> Thank you
> >>
> >> Kind regards,
> >> Nico Schlebusch
> >> nicoschl@gmail.com <ma...@gmail.com>
> >>
> >>
> >> On 07/12/2016 12:22, Nico Schlebusch wrote:
> >>> Good day,
> >>>
> >>> I'm using the @EntityListeners(AuditEntityListener.class) and
> >>> @CreatedOn, @ModifiedOn and @ModifiedBy annotations on an Entity bean
> >>> with the difference that I have a custom implementation of
> >>> java.time.ChronoLocalDateTime which converts any LocalDateTime +
> >>> ZoneOffset OR a ZonedDateTime to be the UTC date & time.
> >>>
> >>>      public class UTCDateTime implements
> >>>      ChronoLocalDateTime<LocalDate>, Serializable {
> >>>
> >>>        private static final long serialVersionUID =
> 6492792765662073566L;
> >>>        private static final ZoneOffset UTC = ZoneOffset.UTC;
> >>>        private final LocalDateTime datetime;
> >>>
> >>>        // a lot of other details left out
> >>>      }
> >>>
> >>> The entity bean parts
> >>>
> >>>      @MappedSuperclass
> >>>      public class InsertableAuditableBean extends BaseBean implements
> >>>      InsertableAuditable {
> >>>
> >>>        @NotNull
> >>>        @Size(min = 1, max = 50)
> >>>        @Column(name = "zz_inserted_by", length = 50, nullable = false)
> >>>        private String insertedBy;
> >>>
> >>>      @CreatedOn
> >>>        @NotNull
> >>>        @Temporal(value = TemporalType.TIMESTAMP)
> >>>        @Column(name = "zz_inserted_on", nullable = false)
> >>>        private UTCDateTime insertedOn;
> >>>
> >>>        // getters & setters
> >>>      }
> >>>
> >>>      @MappedSuperclass
> >>>      public class UpdateableAuditableBean extends
> >>>      InsertableAuditableBean implements UpdateableAuditable {
> >>>
> >>>      @ModifiedBy
> >>>        @Size(min = 1, max = 50)
> >>>        @Column(name = "zz_updated_by", length = 50, nullable = true)
> >>>        private String updatedBy;
> >>>
> >>>      @ModifiedOn
> >>>        @Temporal(value = TemporalType.TIMESTAMP)
> >>>        @Column(name = "zz_updated_on", nullable = true)
> >>>        private UTCDateTime updatedOn;
> >>>
> >>>        // getters & setters
> >>>      }
> >>>
> >>>      @Entity
> >>>      @EntityListeners(AuditEntityListener.class)
> >>>      @Table(schema = "data", name = "manufacturer", uniqueConstraints
> = {
> >>>          @UniqueConstraint(columnNames = { "man_name", "man_country" })
> >>>      })
> >>>      @AttributeOverrides({
> >>>          @AttributeOverride(name = "primaryKey", column = @Column(name
> >>>      = "man_serial")),
> >>>          @AttributeOverride(name = "insertedBy", column = @Column(name
> >>>      = "man_inserted_by")),
> >>>          @AttributeOverride(name = "insertedOn", column = @Column(name
> >>>      = "man_inserted_on")),
> >>>          @AttributeOverride(name = "updatedBy", column = @Column(name =
> >>>      "man_updated_by")),
> >>>          @AttributeOverride(name = "updatedOn", column = @Column(name =
> >>>      "man_updated_on"))
> >>>      })
> >>>      @SequenceGenerator(name = "default_seq", schema = "data",
> >>>      sequenceName = "manufacturer_man_serial_seq",
> >>>          allocationSize = 1)
> >>>      public class Manufacturer extends MirroredUpdateableAuditableBean
> >>>      implements IManufacturer {
> >>>        // nothing special here
> >>>      }
> >>>
> >>> There is also a custom AttributeConverter for the UTCDateTime class
> >>> because the epoch value is saved in the database.
> >>>
> >>>      @Converter(autoApply = true)
> >>>      public class UTCDateTimePersistenceConverter implements
> >>>      AttributeConverter<UTCDateTime, Long> {
> >>>
> >>>        @Override
> >>>        public Long convertToDatabaseColumn(final UTCDateTime
> entityValue)
> >> {
> >>>          Long res = null;
> >>>          if (entityValue != null) {
> >>>            res = entityValue.toMillis();
> >>>          }
> >>>          return res;
> >>>        }
> >>>
> >>>        @Override
> >>>        public UTCDateTime convertToEntityAttribute(final Long
> >>>      databaseValue) {
> >>>          UTCDateTime res = null;
> >>>          if (databaseValue != null) {
> >>>            res = new UTCDateTime(Instant.ofEpochMilli(databaseValue));
> >>>          }
> >>>          return res;
> >>>        }
> >>>      }
> >>>
> >>> Now when I persist the entity I get the following exception (the last
> >>> bit with the real cause):
> >>>
> >>>      Caused by:
> >>>      org.apache.deltaspike.data.api.QueryInvocationException: Failed
> >>>      calling Repository:
> >>>
> >>
>  [Repository=systems.apace.data.manufacturer.model.dao.ManufacturerDAO,entity=systems.apace.data.manufacturer.model.Manufacturer,method=persist,exception=class
> >>>      java.lang.reflect.InvocationTargetException,message=null
> >>>              at
> >>>
> >>
>  systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
> >>>      Caused by: java.lang.reflect.InvocationTargetException
> >>>              at
> >>>
> >>
>  systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
> >>>      Caused by:
> >>>      org.apache.deltaspike.data.impl.audit.AuditPropertyException:
> >>>      Failed to set property Manufacturer.insertedOn, is this a temporal
> >>>      type?
> >>>              at
> >>>
> >>
>  systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
> >>>      Caused by: java.lang.IllegalArgumentException: Annotated field is
> >>>      not a date class: class za.co.t9.common.utils.time.UTCDateTime
> >>>              at
> >>>
> >>
>  systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
> >>> Is there a way to implement my own
> >>> org.apache.deltaspike.data.impl.audit.PrePersistAuditListener and
> >>> org.apache.deltaspike.data.impl.audit.PreUpdateAuditListener and use
> >>> them to create the instance of UTCDateTime?
> >>>
> >>> Would it be correct to write my own EntityListener -->
> >>> UTCDateTimeAuditListener and use it
> >>> @EntityListeners(UTCDateTimeAuditEntityListener.class) where
> >>> UTCDateTimeAuditListener follows the
> >>> org.apache.deltaspike.data.impl.audit.AuditEntityListener approach?
> >>> Secondly, do I need to use a CDI Qualifier somewhere to make sure that
> >>> my UTCDateTimeAuditEntityListener gets a reference to the correct
> >>> PrePersistAuditListener and PreUpdateAuditListener that knows how to
> >>> construct the UTCDateTime instance?
> >>>
> >>> Lastly, I don't know if it is relevant, but where does
> >>> org.apache.deltaspike.data.impl.audit.TimestampsProvider fit into this
> >>> scenario?
> >>>
> >>> Thank you for your time
> >>>
> >>> Kind regards,
> >>> Nico Schlebusch
> >>> nicoschl@gmail.com <ma...@gmail.com>
> >>>
> >>>
> >>
> >>
> >>
>
>
>

Re: DeltaSpike Data - Custom PrePersistAuditListener and PreUpdateAuditListener

Posted by Nico Schlebusch <ni...@gmail.com>.
John,

That loop executes the number of times there are implementations of the 
PrePersistAuditListener. When I have my own implementation deployed it 
executes 3 times. The PrincipalProvider, my custom implementation 
(UTCDateTimeAuditProvider) and then TimestampsProvider are executed in 
that order.

Kind regards,
Nico Schlebusch
nicoschl@gmail.com <ma...@gmail.com>


On 20/12/2016 16:33, John D. Ament wrote:
> Nico,
>
> There's a for loop here
> https://github.com/apache/deltaspike/blob/master/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/audit/AuditEntityListener.java#L38
>
> How many times does this for loop execute?
>
> John
>
> On Tue, Dec 20, 2016 at 9:23 AM Nico Schlebusch <ni...@gmail.com> wrote:
>
>> Hi John,
>>
>> Thanks for the answer.
>>
>> The AuditEntityListener is called once from my debugging sessions.
>>
>> I'll definitely raise a feature request, it might just not be in the next
>> 2 weeks. Would the feature request be to take @Alternative beans into
>> considerations when looking up the beans that implements the 2 interfaces,
>> PrePersistAuditListener & PreUpdateAuditListener? Meaning that lines 40-41
>> and 53-54 from the link below, need to filter out the @Default beans when
>> an @Alternative is available? Or should I phrase it differently?
>>
>> Kind regards,
>> Nico Schlebusch
>> nicoschl@gmail.com
>>
>>
>> On 20/12/2016 15:56, John D. Ament wrote:
>>
>> Nico,
>>
>> Seems the logic in DeltaSpike is to loop through the beans.  Can you check
>> if you're seeing this loop is called multiple times?
>> https://github.com/apache/deltaspike/blob/master/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/audit/AuditEntityListener.java
>>
>> Anyways, would be good to have this support direct in deltaspike.  Mind
>> raising a feature request?
>> https://issues.apache.org/jira/browse/DELTASPIKE
>>
>> John
>>
>> On Tue, Dec 13, 2016 at 2:58 AM Nico Schlebusch <ni...@gmail.com>
>> wrote:
>>
>> Good day,
>>
>> I have made some progress in answering my question, but I'm facing a new
>> problem. Please see the updated Q on SO -
>>
>> http://stackoverflow.com/questions/41057116/deltaspike-data-cdi-jpa-custom-prepersistauditlistener-and-preupdateauditlis
>>
>> Thank you
>>
>> Kind regards,
>> Nico Schlebusch
>> nicoschl@gmail.com <ma...@gmail.com>
>>
>>
>> On 07/12/2016 12:22, Nico Schlebusch wrote:
>>> Good day,
>>>
>>> I'm using the @EntityListeners(AuditEntityListener.class) and
>>> @CreatedOn, @ModifiedOn and @ModifiedBy annotations on an Entity bean
>>> with the difference that I have a custom implementation of
>>> java.time.ChronoLocalDateTime which converts any LocalDateTime +
>>> ZoneOffset OR a ZonedDateTime to be the UTC date & time.
>>>
>>>      public class UTCDateTime implements
>>>      ChronoLocalDateTime<LocalDate>, Serializable {
>>>
>>>        private static final long serialVersionUID = 6492792765662073566L;
>>>        private static final ZoneOffset UTC = ZoneOffset.UTC;
>>>        private final LocalDateTime datetime;
>>>
>>>        // a lot of other details left out
>>>      }
>>>
>>> The entity bean parts
>>>
>>>      @MappedSuperclass
>>>      public class InsertableAuditableBean extends BaseBean implements
>>>      InsertableAuditable {
>>>
>>>        @NotNull
>>>        @Size(min = 1, max = 50)
>>>        @Column(name = "zz_inserted_by", length = 50, nullable = false)
>>>        private String insertedBy;
>>>
>>>      @CreatedOn
>>>        @NotNull
>>>        @Temporal(value = TemporalType.TIMESTAMP)
>>>        @Column(name = "zz_inserted_on", nullable = false)
>>>        private UTCDateTime insertedOn;
>>>
>>>        // getters & setters
>>>      }
>>>
>>>      @MappedSuperclass
>>>      public class UpdateableAuditableBean extends
>>>      InsertableAuditableBean implements UpdateableAuditable {
>>>
>>>      @ModifiedBy
>>>        @Size(min = 1, max = 50)
>>>        @Column(name = "zz_updated_by", length = 50, nullable = true)
>>>        private String updatedBy;
>>>
>>>      @ModifiedOn
>>>        @Temporal(value = TemporalType.TIMESTAMP)
>>>        @Column(name = "zz_updated_on", nullable = true)
>>>        private UTCDateTime updatedOn;
>>>
>>>        // getters & setters
>>>      }
>>>
>>>      @Entity
>>>      @EntityListeners(AuditEntityListener.class)
>>>      @Table(schema = "data", name = "manufacturer", uniqueConstraints = {
>>>          @UniqueConstraint(columnNames = { "man_name", "man_country" })
>>>      })
>>>      @AttributeOverrides({
>>>          @AttributeOverride(name = "primaryKey", column = @Column(name
>>>      = "man_serial")),
>>>          @AttributeOverride(name = "insertedBy", column = @Column(name
>>>      = "man_inserted_by")),
>>>          @AttributeOverride(name = "insertedOn", column = @Column(name
>>>      = "man_inserted_on")),
>>>          @AttributeOverride(name = "updatedBy", column = @Column(name =
>>>      "man_updated_by")),
>>>          @AttributeOverride(name = "updatedOn", column = @Column(name =
>>>      "man_updated_on"))
>>>      })
>>>      @SequenceGenerator(name = "default_seq", schema = "data",
>>>      sequenceName = "manufacturer_man_serial_seq",
>>>          allocationSize = 1)
>>>      public class Manufacturer extends MirroredUpdateableAuditableBean
>>>      implements IManufacturer {
>>>        // nothing special here
>>>      }
>>>
>>> There is also a custom AttributeConverter for the UTCDateTime class
>>> because the epoch value is saved in the database.
>>>
>>>      @Converter(autoApply = true)
>>>      public class UTCDateTimePersistenceConverter implements
>>>      AttributeConverter<UTCDateTime, Long> {
>>>
>>>        @Override
>>>        public Long convertToDatabaseColumn(final UTCDateTime entityValue)
>> {
>>>          Long res = null;
>>>          if (entityValue != null) {
>>>            res = entityValue.toMillis();
>>>          }
>>>          return res;
>>>        }
>>>
>>>        @Override
>>>        public UTCDateTime convertToEntityAttribute(final Long
>>>      databaseValue) {
>>>          UTCDateTime res = null;
>>>          if (databaseValue != null) {
>>>            res = new UTCDateTime(Instant.ofEpochMilli(databaseValue));
>>>          }
>>>          return res;
>>>        }
>>>      }
>>>
>>> Now when I persist the entity I get the following exception (the last
>>> bit with the real cause):
>>>
>>>      Caused by:
>>>      org.apache.deltaspike.data.api.QueryInvocationException: Failed
>>>      calling Repository:
>>>
>>   [Repository=systems.apace.data.manufacturer.model.dao.ManufacturerDAO,entity=systems.apace.data.manufacturer.model.Manufacturer,method=persist,exception=class
>>>      java.lang.reflect.InvocationTargetException,message=null
>>>              at
>>>
>>   systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
>>>      Caused by: java.lang.reflect.InvocationTargetException
>>>              at
>>>
>>   systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
>>>      Caused by:
>>>      org.apache.deltaspike.data.impl.audit.AuditPropertyException:
>>>      Failed to set property Manufacturer.insertedOn, is this a temporal
>>>      type?
>>>              at
>>>
>>   systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
>>>      Caused by: java.lang.IllegalArgumentException: Annotated field is
>>>      not a date class: class za.co.t9.common.utils.time.UTCDateTime
>>>              at
>>>
>>   systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
>>> Is there a way to implement my own
>>> org.apache.deltaspike.data.impl.audit.PrePersistAuditListener and
>>> org.apache.deltaspike.data.impl.audit.PreUpdateAuditListener and use
>>> them to create the instance of UTCDateTime?
>>>
>>> Would it be correct to write my own EntityListener -->
>>> UTCDateTimeAuditListener and use it
>>> @EntityListeners(UTCDateTimeAuditEntityListener.class) where
>>> UTCDateTimeAuditListener follows the
>>> org.apache.deltaspike.data.impl.audit.AuditEntityListener approach?
>>> Secondly, do I need to use a CDI Qualifier somewhere to make sure that
>>> my UTCDateTimeAuditEntityListener gets a reference to the correct
>>> PrePersistAuditListener and PreUpdateAuditListener that knows how to
>>> construct the UTCDateTime instance?
>>>
>>> Lastly, I don't know if it is relevant, but where does
>>> org.apache.deltaspike.data.impl.audit.TimestampsProvider fit into this
>>> scenario?
>>>
>>> Thank you for your time
>>>
>>> Kind regards,
>>> Nico Schlebusch
>>> nicoschl@gmail.com <ma...@gmail.com>
>>>
>>>
>>
>>
>>



Re: DeltaSpike Data - Custom PrePersistAuditListener and PreUpdateAuditListener

Posted by "John D. Ament" <jo...@apache.org>.
Nico,

There's a for loop here
https://github.com/apache/deltaspike/blob/master/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/audit/AuditEntityListener.java#L38

How many times does this for loop execute?

John

On Tue, Dec 20, 2016 at 9:23 AM Nico Schlebusch <ni...@gmail.com> wrote:

> Hi John,
>
> Thanks for the answer.
>
> The AuditEntityListener is called once from my debugging sessions.
>
> I'll definitely raise a feature request, it might just not be in the next
> 2 weeks. Would the feature request be to take @Alternative beans into
> considerations when looking up the beans that implements the 2 interfaces,
> PrePersistAuditListener & PreUpdateAuditListener? Meaning that lines 40-41
> and 53-54 from the link below, need to filter out the @Default beans when
> an @Alternative is available? Or should I phrase it differently?
>
> Kind regards,
> Nico Schlebusch
> nicoschl@gmail.com
>
>
> On 20/12/2016 15:56, John D. Ament wrote:
>
> Nico,
>
> Seems the logic in DeltaSpike is to loop through the beans.  Can you check
> if you're seeing this loop is called multiple times?
> https://github.com/apache/deltaspike/blob/master/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/audit/AuditEntityListener.java
>
> Anyways, would be good to have this support direct in deltaspike.  Mind
> raising a feature request?
> https://issues.apache.org/jira/browse/DELTASPIKE
>
> John
>
> On Tue, Dec 13, 2016 at 2:58 AM Nico Schlebusch <ni...@gmail.com>
> wrote:
>
> Good day,
>
> I have made some progress in answering my question, but I'm facing a new
> problem. Please see the updated Q on SO -
>
> http://stackoverflow.com/questions/41057116/deltaspike-data-cdi-jpa-custom-prepersistauditlistener-and-preupdateauditlis
>
> Thank you
>
> Kind regards,
> Nico Schlebusch
> nicoschl@gmail.com <ma...@gmail.com>
>
>
> On 07/12/2016 12:22, Nico Schlebusch wrote:
> > Good day,
> >
> > I'm using the @EntityListeners(AuditEntityListener.class) and
> > @CreatedOn, @ModifiedOn and @ModifiedBy annotations on an Entity bean
> > with the difference that I have a custom implementation of
> > java.time.ChronoLocalDateTime which converts any LocalDateTime +
> > ZoneOffset OR a ZonedDateTime to be the UTC date & time.
> >
> >     public class UTCDateTime implements
> >     ChronoLocalDateTime<LocalDate>, Serializable {
> >
> >       private static final long serialVersionUID = 6492792765662073566L;
> >       private static final ZoneOffset UTC = ZoneOffset.UTC;
> >       private final LocalDateTime datetime;
> >
> >       // a lot of other details left out
> >     }
> >
> > The entity bean parts
> >
> >     @MappedSuperclass
> >     public class InsertableAuditableBean extends BaseBean implements
> >     InsertableAuditable {
> >
> >       @NotNull
> >       @Size(min = 1, max = 50)
> >       @Column(name = "zz_inserted_by", length = 50, nullable = false)
> >       private String insertedBy;
> >
> >     @CreatedOn
> >       @NotNull
> >       @Temporal(value = TemporalType.TIMESTAMP)
> >       @Column(name = "zz_inserted_on", nullable = false)
> >       private UTCDateTime insertedOn;
> >
> >       // getters & setters
> >     }
> >
> >     @MappedSuperclass
> >     public class UpdateableAuditableBean extends
> >     InsertableAuditableBean implements UpdateableAuditable {
> >
> >     @ModifiedBy
> >       @Size(min = 1, max = 50)
> >       @Column(name = "zz_updated_by", length = 50, nullable = true)
> >       private String updatedBy;
> >
> >     @ModifiedOn
> >       @Temporal(value = TemporalType.TIMESTAMP)
> >       @Column(name = "zz_updated_on", nullable = true)
> >       private UTCDateTime updatedOn;
> >
> >       // getters & setters
> >     }
> >
> >     @Entity
> >     @EntityListeners(AuditEntityListener.class)
> >     @Table(schema = "data", name = "manufacturer", uniqueConstraints = {
> >         @UniqueConstraint(columnNames = { "man_name", "man_country" })
> >     })
> >     @AttributeOverrides({
> >         @AttributeOverride(name = "primaryKey", column = @Column(name
> >     = "man_serial")),
> >         @AttributeOverride(name = "insertedBy", column = @Column(name
> >     = "man_inserted_by")),
> >         @AttributeOverride(name = "insertedOn", column = @Column(name
> >     = "man_inserted_on")),
> >         @AttributeOverride(name = "updatedBy", column = @Column(name =
> >     "man_updated_by")),
> >         @AttributeOverride(name = "updatedOn", column = @Column(name =
> >     "man_updated_on"))
> >     })
> >     @SequenceGenerator(name = "default_seq", schema = "data",
> >     sequenceName = "manufacturer_man_serial_seq",
> >         allocationSize = 1)
> >     public class Manufacturer extends MirroredUpdateableAuditableBean
> >     implements IManufacturer {
> >       // nothing special here
> >     }
> >
> > There is also a custom AttributeConverter for the UTCDateTime class
> > because the epoch value is saved in the database.
> >
> >     @Converter(autoApply = true)
> >     public class UTCDateTimePersistenceConverter implements
> >     AttributeConverter<UTCDateTime, Long> {
> >
> >       @Override
> >       public Long convertToDatabaseColumn(final UTCDateTime entityValue)
> {
> >         Long res = null;
> >         if (entityValue != null) {
> >           res = entityValue.toMillis();
> >         }
> >         return res;
> >       }
> >
> >       @Override
> >       public UTCDateTime convertToEntityAttribute(final Long
> >     databaseValue) {
> >         UTCDateTime res = null;
> >         if (databaseValue != null) {
> >           res = new UTCDateTime(Instant.ofEpochMilli(databaseValue));
> >         }
> >         return res;
> >       }
> >     }
> >
> > Now when I persist the entity I get the following exception (the last
> > bit with the real cause):
> >
> >     Caused by:
> >     org.apache.deltaspike.data.api.QueryInvocationException: Failed
> >     calling Repository:
> >
>  [Repository=systems.apace.data.manufacturer.model.dao.ManufacturerDAO,entity=systems.apace.data.manufacturer.model.Manufacturer,method=persist,exception=class
> >     java.lang.reflect.InvocationTargetException,message=null
> >             at
> >
>  systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
> >     Caused by: java.lang.reflect.InvocationTargetException
> >             at
> >
>  systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
> >     Caused by:
> >     org.apache.deltaspike.data.impl.audit.AuditPropertyException:
> >     Failed to set property Manufacturer.insertedOn, is this a temporal
> >     type?
> >             at
> >
>  systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
> >     Caused by: java.lang.IllegalArgumentException: Annotated field is
> >     not a date class: class za.co.t9.common.utils.time.UTCDateTime
> >             at
> >
>  systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
> >
> > Is there a way to implement my own
> > org.apache.deltaspike.data.impl.audit.PrePersistAuditListener and
> > org.apache.deltaspike.data.impl.audit.PreUpdateAuditListener and use
> > them to create the instance of UTCDateTime?
> >
> > Would it be correct to write my own EntityListener -->
> > UTCDateTimeAuditListener and use it
> > @EntityListeners(UTCDateTimeAuditEntityListener.class) where
> > UTCDateTimeAuditListener follows the
> > org.apache.deltaspike.data.impl.audit.AuditEntityListener approach?
> > Secondly, do I need to use a CDI Qualifier somewhere to make sure that
> > my UTCDateTimeAuditEntityListener gets a reference to the correct
> > PrePersistAuditListener and PreUpdateAuditListener that knows how to
> > construct the UTCDateTime instance?
> >
> > Lastly, I don't know if it is relevant, but where does
> > org.apache.deltaspike.data.impl.audit.TimestampsProvider fit into this
> > scenario?
> >
> > Thank you for your time
> >
> > Kind regards,
> > Nico Schlebusch
> > nicoschl@gmail.com <ma...@gmail.com>
> >
> >
>
>
>
>
>

Re: DeltaSpike Data - Custom PrePersistAuditListener and PreUpdateAuditListener

Posted by Nico Schlebusch <ni...@gmail.com>.
Hi John,

Thanks for the answer.

The AuditEntityListener is called once from my debugging sessions.

I'll definitely raise a feature request, it might just not be in the 
next 2 weeks. Would the feature request be to take @Alternative beans 
into considerations when looking up the beans that implements the 2 
interfaces, PrePersistAuditListener & PreUpdateAuditListener? Meaning 
that lines 40-41 and 53-54 from the link below, need to filter out the 
@Default beans when an @Alternative is available? Or should I phrase it 
differently?

Kind regards,
Nico Schlebusch
nicoschl@gmail.com <ma...@gmail.com>


On 20/12/2016 15:56, John D. Ament wrote:
> Nico,
>
> Seems the logic in DeltaSpike is to loop through the beans.  Can you 
> check if you're seeing this loop is called multiple times? 
> https://github.com/apache/deltaspike/blob/master/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/audit/AuditEntityListener.java
>
> Anyways, would be good to have this support direct in deltaspike.  
> Mind raising a feature request? 
> https://issues.apache.org/jira/browse/DELTASPIKE
>
> John
>
> On Tue, Dec 13, 2016 at 2:58 AM Nico Schlebusch <nicoschl@gmail.com 
> <ma...@gmail.com>> wrote:
>
>     Good day,
>
>     I have made some progress in answering my question, but I'm facing
>     a new
>     problem. Please see the updated Q on SO -
>     http://stackoverflow.com/questions/41057116/deltaspike-data-cdi-jpa-custom-prepersistauditlistener-and-preupdateauditlis
>
>     Thank you
>
>     Kind regards,
>     Nico Schlebusch
>     nicoschl@gmail.com <ma...@gmail.com>
>     <mailto:nicoschl@gmail.com <ma...@gmail.com>>
>
>
>     On 07/12/2016 12:22, Nico Schlebusch wrote:
>     > Good day,
>     >
>     > I'm using the @EntityListeners(AuditEntityListener.class) and
>     > @CreatedOn, @ModifiedOn and @ModifiedBy annotations on an Entity
>     bean
>     > with the difference that I have a custom implementation of
>     > java.time.ChronoLocalDateTime which converts any LocalDateTime +
>     > ZoneOffset OR a ZonedDateTime to be the UTC date & time.
>     >
>     >     public class UTCDateTime implements
>     >     ChronoLocalDateTime<LocalDate>, Serializable {
>     >
>     >       private static final long serialVersionUID =
>     6492792765662073566L;
>     >       private static final ZoneOffset UTC = ZoneOffset.UTC;
>     >       private final LocalDateTime datetime;
>     >
>     >       // a lot of other details left out
>     >     }
>     >
>     > The entity bean parts
>     >
>     >     @MappedSuperclass
>     >     public class InsertableAuditableBean extends BaseBean implements
>     >     InsertableAuditable {
>     >
>     >       @NotNull
>     >       @Size(min = 1, max = 50)
>     >       @Column(name = "zz_inserted_by", length = 50, nullable =
>     false)
>     >       private String insertedBy;
>     >
>     >     @CreatedOn
>     >       @NotNull
>     >       @Temporal(value = TemporalType.TIMESTAMP)
>     >       @Column(name = "zz_inserted_on", nullable = false)
>     >       private UTCDateTime insertedOn;
>     >
>     >       // getters & setters
>     >     }
>     >
>     >     @MappedSuperclass
>     >     public class UpdateableAuditableBean extends
>     >     InsertableAuditableBean implements UpdateableAuditable {
>     >
>     >     @ModifiedBy
>     >       @Size(min = 1, max = 50)
>     >       @Column(name = "zz_updated_by", length = 50, nullable = true)
>     >       private String updatedBy;
>     >
>     >     @ModifiedOn
>     >       @Temporal(value = TemporalType.TIMESTAMP)
>     >       @Column(name = "zz_updated_on", nullable = true)
>     >       private UTCDateTime updatedOn;
>     >
>     >       // getters & setters
>     >     }
>     >
>     >     @Entity
>     >     @EntityListeners(AuditEntityListener.class)
>     >     @Table(schema = "data", name = "manufacturer",
>     uniqueConstraints = {
>     >         @UniqueConstraint(columnNames = { "man_name",
>     "man_country" })
>     >     })
>     >     @AttributeOverrides({
>     >         @AttributeOverride(name = "primaryKey", column =
>     @Column(name
>     >     = "man_serial")),
>     >         @AttributeOverride(name = "insertedBy", column =
>     @Column(name
>     >     = "man_inserted_by")),
>     >         @AttributeOverride(name = "insertedOn", column =
>     @Column(name
>     >     = "man_inserted_on")),
>     >         @AttributeOverride(name = "updatedBy", column =
>     @Column(name =
>     >     "man_updated_by")),
>     >         @AttributeOverride(name = "updatedOn", column =
>     @Column(name =
>     >     "man_updated_on"))
>     >     })
>     >     @SequenceGenerator(name = "default_seq", schema = "data",
>     >     sequenceName = "manufacturer_man_serial_seq",
>     >         allocationSize = 1)
>     >     public class Manufacturer extends
>     MirroredUpdateableAuditableBean
>     >     implements IManufacturer {
>     >       // nothing special here
>     >     }
>     >
>     > There is also a custom AttributeConverter for the UTCDateTime class
>     > because the epoch value is saved in the database.
>     >
>     >     @Converter(autoApply = true)
>     >     public class UTCDateTimePersistenceConverter implements
>     >     AttributeConverter<UTCDateTime, Long> {
>     >
>     >       @Override
>     >       public Long convertToDatabaseColumn(final UTCDateTime
>     entityValue) {
>     >         Long res = null;
>     >         if (entityValue != null) {
>     >           res = entityValue.toMillis();
>     >         }
>     >         return res;
>     >       }
>     >
>     >       @Override
>     >       public UTCDateTime convertToEntityAttribute(final Long
>     >     databaseValue) {
>     >         UTCDateTime res = null;
>     >         if (databaseValue != null) {
>     >           res = new
>     UTCDateTime(Instant.ofEpochMilli(databaseValue));
>     >         }
>     >         return res;
>     >       }
>     >     }
>     >
>     > Now when I persist the entity I get the following exception (the
>     last
>     > bit with the real cause):
>     >
>     >     Caused by:
>     >  org.apache.deltaspike.data.api.QueryInvocationException: Failed
>     >     calling Repository:
>     >
>      [Repository=systems.apace.data.manufacturer.model.dao.ManufacturerDAO,entity=systems.apace.data.manufacturer.model.Manufacturer,method=persist,exception=class
>     >  java.lang.reflect.InvocationTargetException,message=null
>     >             at
>     >
>      systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
>     >     Caused by: java.lang.reflect.InvocationTargetException
>     >             at
>     >
>      systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
>     >     Caused by:
>     >  org.apache.deltaspike.data.impl.audit.AuditPropertyException:
>     >     Failed to set property Manufacturer.insertedOn, is this a
>     temporal
>     >     type?
>     >             at
>     >
>      systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
>     >     Caused by: java.lang.IllegalArgumentException: Annotated
>     field is
>     >     not a date class: class za.co.t9.common.utils.time.UTCDateTime
>     >             at
>     >
>      systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
>     >
>     > Is there a way to implement my own
>     > org.apache.deltaspike.data.impl.audit.PrePersistAuditListener and
>     > org.apache.deltaspike.data.impl.audit.PreUpdateAuditListener and use
>     > them to create the instance of UTCDateTime?
>     >
>     > Would it be correct to write my own EntityListener -->
>     > UTCDateTimeAuditListener and use it
>     > @EntityListeners(UTCDateTimeAuditEntityListener.class) where
>     > UTCDateTimeAuditListener follows the
>     > org.apache.deltaspike.data.impl.audit.AuditEntityListener approach?
>     > Secondly, do I need to use a CDI Qualifier somewhere to make
>     sure that
>     > my UTCDateTimeAuditEntityListener gets a reference to the correct
>     > PrePersistAuditListener and PreUpdateAuditListener that knows how to
>     > construct the UTCDateTime instance?
>     >
>     > Lastly, I don't know if it is relevant, but where does
>     > org.apache.deltaspike.data.impl.audit.TimestampsProvider fit
>     into this
>     > scenario?
>     >
>     > Thank you for your time
>     >
>     > Kind regards,
>     > Nico Schlebusch
>     > nicoschl@gmail.com <ma...@gmail.com>
>     <mailto:nicoschl@gmail.com <ma...@gmail.com>>
>     >
>     >
>
>



Re: DeltaSpike Data - Custom PrePersistAuditListener and PreUpdateAuditListener

Posted by "John D. Ament" <jo...@apache.org>.
Nico,

Seems the logic in DeltaSpike is to loop through the beans.  Can you check
if you're seeing this loop is called multiple times?
https://github.com/apache/deltaspike/blob/master/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/audit/AuditEntityListener.java

Anyways, would be good to have this support direct in deltaspike.  Mind
raising a feature request? https://issues.apache.org/jira/browse/DELTASPIKE

John

On Tue, Dec 13, 2016 at 2:58 AM Nico Schlebusch <ni...@gmail.com> wrote:

> Good day,
>
> I have made some progress in answering my question, but I'm facing a new
> problem. Please see the updated Q on SO -
>
> http://stackoverflow.com/questions/41057116/deltaspike-data-cdi-jpa-custom-prepersistauditlistener-and-preupdateauditlis
>
> Thank you
>
> Kind regards,
> Nico Schlebusch
> nicoschl@gmail.com <ma...@gmail.com>
>
>
> On 07/12/2016 12:22, Nico Schlebusch wrote:
> > Good day,
> >
> > I'm using the @EntityListeners(AuditEntityListener.class) and
> > @CreatedOn, @ModifiedOn and @ModifiedBy annotations on an Entity bean
> > with the difference that I have a custom implementation of
> > java.time.ChronoLocalDateTime which converts any LocalDateTime +
> > ZoneOffset OR a ZonedDateTime to be the UTC date & time.
> >
> >     public class UTCDateTime implements
> >     ChronoLocalDateTime<LocalDate>, Serializable {
> >
> >       private static final long serialVersionUID = 6492792765662073566L;
> >       private static final ZoneOffset UTC = ZoneOffset.UTC;
> >       private final LocalDateTime datetime;
> >
> >       // a lot of other details left out
> >     }
> >
> > The entity bean parts
> >
> >     @MappedSuperclass
> >     public class InsertableAuditableBean extends BaseBean implements
> >     InsertableAuditable {
> >
> >       @NotNull
> >       @Size(min = 1, max = 50)
> >       @Column(name = "zz_inserted_by", length = 50, nullable = false)
> >       private String insertedBy;
> >
> >     @CreatedOn
> >       @NotNull
> >       @Temporal(value = TemporalType.TIMESTAMP)
> >       @Column(name = "zz_inserted_on", nullable = false)
> >       private UTCDateTime insertedOn;
> >
> >       // getters & setters
> >     }
> >
> >     @MappedSuperclass
> >     public class UpdateableAuditableBean extends
> >     InsertableAuditableBean implements UpdateableAuditable {
> >
> >     @ModifiedBy
> >       @Size(min = 1, max = 50)
> >       @Column(name = "zz_updated_by", length = 50, nullable = true)
> >       private String updatedBy;
> >
> >     @ModifiedOn
> >       @Temporal(value = TemporalType.TIMESTAMP)
> >       @Column(name = "zz_updated_on", nullable = true)
> >       private UTCDateTime updatedOn;
> >
> >       // getters & setters
> >     }
> >
> >     @Entity
> >     @EntityListeners(AuditEntityListener.class)
> >     @Table(schema = "data", name = "manufacturer", uniqueConstraints = {
> >         @UniqueConstraint(columnNames = { "man_name", "man_country" })
> >     })
> >     @AttributeOverrides({
> >         @AttributeOverride(name = "primaryKey", column = @Column(name
> >     = "man_serial")),
> >         @AttributeOverride(name = "insertedBy", column = @Column(name
> >     = "man_inserted_by")),
> >         @AttributeOverride(name = "insertedOn", column = @Column(name
> >     = "man_inserted_on")),
> >         @AttributeOverride(name = "updatedBy", column = @Column(name =
> >     "man_updated_by")),
> >         @AttributeOverride(name = "updatedOn", column = @Column(name =
> >     "man_updated_on"))
> >     })
> >     @SequenceGenerator(name = "default_seq", schema = "data",
> >     sequenceName = "manufacturer_man_serial_seq",
> >         allocationSize = 1)
> >     public class Manufacturer extends MirroredUpdateableAuditableBean
> >     implements IManufacturer {
> >       // nothing special here
> >     }
> >
> > There is also a custom AttributeConverter for the UTCDateTime class
> > because the epoch value is saved in the database.
> >
> >     @Converter(autoApply = true)
> >     public class UTCDateTimePersistenceConverter implements
> >     AttributeConverter<UTCDateTime, Long> {
> >
> >       @Override
> >       public Long convertToDatabaseColumn(final UTCDateTime entityValue)
> {
> >         Long res = null;
> >         if (entityValue != null) {
> >           res = entityValue.toMillis();
> >         }
> >         return res;
> >       }
> >
> >       @Override
> >       public UTCDateTime convertToEntityAttribute(final Long
> >     databaseValue) {
> >         UTCDateTime res = null;
> >         if (databaseValue != null) {
> >           res = new UTCDateTime(Instant.ofEpochMilli(databaseValue));
> >         }
> >         return res;
> >       }
> >     }
> >
> > Now when I persist the entity I get the following exception (the last
> > bit with the real cause):
> >
> >     Caused by:
> >     org.apache.deltaspike.data.api.QueryInvocationException: Failed
> >     calling Repository:
> >
>  [Repository=systems.apace.data.manufacturer.model.dao.ManufacturerDAO,entity=systems.apace.data.manufacturer.model.Manufacturer,method=persist,exception=class
> >     java.lang.reflect.InvocationTargetException,message=null
> >             at
> >
>  systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
> >     Caused by: java.lang.reflect.InvocationTargetException
> >             at
> >
>  systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
> >     Caused by:
> >     org.apache.deltaspike.data.impl.audit.AuditPropertyException:
> >     Failed to set property Manufacturer.insertedOn, is this a temporal
> >     type?
> >             at
> >
>  systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
> >     Caused by: java.lang.IllegalArgumentException: Annotated field is
> >     not a date class: class za.co.t9.common.utils.time.UTCDateTime
> >             at
> >
>  systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
> >
> > Is there a way to implement my own
> > org.apache.deltaspike.data.impl.audit.PrePersistAuditListener and
> > org.apache.deltaspike.data.impl.audit.PreUpdateAuditListener and use
> > them to create the instance of UTCDateTime?
> >
> > Would it be correct to write my own EntityListener -->
> > UTCDateTimeAuditListener and use it
> > @EntityListeners(UTCDateTimeAuditEntityListener.class) where
> > UTCDateTimeAuditListener follows the
> > org.apache.deltaspike.data.impl.audit.AuditEntityListener approach?
> > Secondly, do I need to use a CDI Qualifier somewhere to make sure that
> > my UTCDateTimeAuditEntityListener gets a reference to the correct
> > PrePersistAuditListener and PreUpdateAuditListener that knows how to
> > construct the UTCDateTime instance?
> >
> > Lastly, I don't know if it is relevant, but where does
> > org.apache.deltaspike.data.impl.audit.TimestampsProvider fit into this
> > scenario?
> >
> > Thank you for your time
> >
> > Kind regards,
> > Nico Schlebusch
> > nicoschl@gmail.com <ma...@gmail.com>
> >
> >
>
>
>

Re: DeltaSpike Data - Custom PrePersistAuditListener and PreUpdateAuditListener

Posted by Nico Schlebusch <ni...@gmail.com>.
Good day,

I have made some progress in answering my question, but I'm facing a new 
problem. Please see the updated Q on SO - 
http://stackoverflow.com/questions/41057116/deltaspike-data-cdi-jpa-custom-prepersistauditlistener-and-preupdateauditlis

Thank you

Kind regards,
Nico Schlebusch
nicoschl@gmail.com <ma...@gmail.com>


On 07/12/2016 12:22, Nico Schlebusch wrote:
> Good day,
>
> I'm using the @EntityListeners(AuditEntityListener.class) and 
> @CreatedOn, @ModifiedOn and @ModifiedBy annotations on an Entity bean 
> with the difference that I have a custom implementation of 
> java.time.ChronoLocalDateTime which converts any LocalDateTime + 
> ZoneOffset OR a ZonedDateTime to be the UTC date & time.
>
>     public class UTCDateTime implements
>     ChronoLocalDateTime<LocalDate>, Serializable {
>
>       private static final long serialVersionUID = 6492792765662073566L;
>       private static final ZoneOffset UTC = ZoneOffset.UTC;
>       private final LocalDateTime datetime;
>
>       // a lot of other details left out
>     }
>
> The entity bean parts
>
>     @MappedSuperclass
>     public class InsertableAuditableBean extends BaseBean implements
>     InsertableAuditable {
>
>       @NotNull
>       @Size(min = 1, max = 50)
>       @Column(name = "zz_inserted_by", length = 50, nullable = false)
>       private String insertedBy;
>
>     @CreatedOn
>       @NotNull
>       @Temporal(value = TemporalType.TIMESTAMP)
>       @Column(name = "zz_inserted_on", nullable = false)
>       private UTCDateTime insertedOn;
>
>       // getters & setters
>     }
>
>     @MappedSuperclass
>     public class UpdateableAuditableBean extends
>     InsertableAuditableBean implements UpdateableAuditable {
>
>     @ModifiedBy
>       @Size(min = 1, max = 50)
>       @Column(name = "zz_updated_by", length = 50, nullable = true)
>       private String updatedBy;
>
>     @ModifiedOn
>       @Temporal(value = TemporalType.TIMESTAMP)
>       @Column(name = "zz_updated_on", nullable = true)
>       private UTCDateTime updatedOn;
>
>       // getters & setters
>     }
>
>     @Entity
>     @EntityListeners(AuditEntityListener.class)
>     @Table(schema = "data", name = "manufacturer", uniqueConstraints = {
>         @UniqueConstraint(columnNames = { "man_name", "man_country" })
>     })
>     @AttributeOverrides({
>         @AttributeOverride(name = "primaryKey", column = @Column(name
>     = "man_serial")),
>         @AttributeOverride(name = "insertedBy", column = @Column(name
>     = "man_inserted_by")),
>         @AttributeOverride(name = "insertedOn", column = @Column(name
>     = "man_inserted_on")),
>         @AttributeOverride(name = "updatedBy", column = @Column(name =
>     "man_updated_by")),
>         @AttributeOverride(name = "updatedOn", column = @Column(name =
>     "man_updated_on"))
>     })
>     @SequenceGenerator(name = "default_seq", schema = "data",
>     sequenceName = "manufacturer_man_serial_seq",
>         allocationSize = 1)
>     public class Manufacturer extends MirroredUpdateableAuditableBean
>     implements IManufacturer {
>       // nothing special here
>     }
>
> There is also a custom AttributeConverter for the UTCDateTime class 
> because the epoch value is saved in the database.
>
>     @Converter(autoApply = true)
>     public class UTCDateTimePersistenceConverter implements
>     AttributeConverter<UTCDateTime, Long> {
>
>       @Override
>       public Long convertToDatabaseColumn(final UTCDateTime entityValue) {
>         Long res = null;
>         if (entityValue != null) {
>           res = entityValue.toMillis();
>         }
>         return res;
>       }
>
>       @Override
>       public UTCDateTime convertToEntityAttribute(final Long
>     databaseValue) {
>         UTCDateTime res = null;
>         if (databaseValue != null) {
>           res = new UTCDateTime(Instant.ofEpochMilli(databaseValue));
>         }
>         return res;
>       }
>     }
>
> Now when I persist the entity I get the following exception (the last 
> bit with the real cause):
>
>     Caused by:
>     org.apache.deltaspike.data.api.QueryInvocationException: Failed
>     calling Repository:
>     [Repository=systems.apace.data.manufacturer.model.dao.ManufacturerDAO,entity=systems.apace.data.manufacturer.model.Manufacturer,method=persist,exception=class
>     java.lang.reflect.InvocationTargetException,message=null
>             at
>     systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
>     Caused by: java.lang.reflect.InvocationTargetException
>             at
>     systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
>     Caused by:
>     org.apache.deltaspike.data.impl.audit.AuditPropertyException:
>     Failed to set property Manufacturer.insertedOn, is this a temporal
>     type?
>             at
>     systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
>     Caused by: java.lang.IllegalArgumentException: Annotated field is
>     not a date class: class za.co.t9.common.utils.time.UTCDateTime
>             at
>     systems.apace.data.manufacturer.services.ManufacturerServiceBeanIntegrationTest.testInsertBean(ManufacturerServiceBeanIntegrationTest.java:55)
>
> Is there a way to implement my own 
> org.apache.deltaspike.data.impl.audit.PrePersistAuditListener and 
> org.apache.deltaspike.data.impl.audit.PreUpdateAuditListener and use 
> them to create the instance of UTCDateTime?
>
> Would it be correct to write my own EntityListener --> 
> UTCDateTimeAuditListener and use it 
> @EntityListeners(UTCDateTimeAuditEntityListener.class) where 
> UTCDateTimeAuditListener follows the 
> org.apache.deltaspike.data.impl.audit.AuditEntityListener approach?
> Secondly, do I need to use a CDI Qualifier somewhere to make sure that 
> my UTCDateTimeAuditEntityListener gets a reference to the correct 
> PrePersistAuditListener and PreUpdateAuditListener that knows how to 
> construct the UTCDateTime instance?
>
> Lastly, I don't know if it is relevant, but where does 
> org.apache.deltaspike.data.impl.audit.TimestampsProvider fit into this 
> scenario?
>
> Thank you for your time
>
> Kind regards,
> Nico Schlebusch
> nicoschl@gmail.com <ma...@gmail.com>
>
>