27 April 2019

blog java orm

Cas interessant pour Email, qui doit faire le lien vers de multiples destinataires et de multiples cc.

Ce que je voudrais faire :

avoir une fonction getTo, qui renvoie une liste de string avec les adresses, et une fonction getCc, qui fait la même chose.

Je vais essayer de m'approcher de ça.

Mapping avec des Entités EmailParticipant.

Une bonne analyse sur la question de la composition (vs agrégation) :
* JPA Aggregation versus composition and deleting of child entities

Comme il n'y à pas d'Id spécifique, il faut créer une sous classe composite sur le modèle de :

J'ai une classe EmailParticipant, qui possède un EmailParticipantId avec les même champs.

On peut simplifier avec ClassId en indiquant la classe elle même.
* SQL JPA - Multiple columns as primary key
** La bonne réponse

Bilan provisoire

On arrive au resultat suivant :

{
	"emailAccount":"devkdm@festival-cannes.fr",
	"emailUid":"test1",
	"subject":"Ce mail n'existe pas",
	"from":"hnlocher@cst.fr",
	"sendDate":"2019-04-24T07:08:00.000+0000",
	"emldirpath":"2019.04.10+10.52.23-2-%3Cdfdce60f-1d3d-403f-2c2b-c5b642d296a6%40cst.fr%3E/",
	"emlfilename":"mail.eml",
	"participants":
		[
			{"relation":"TO","address":"devkdm@festival-cannes.fr"},
			{"relation":"CC","address":"hnlocher@free.fr"}
		]
	}

J'aurais voulu plutot :

"to":
	[
		{"devkdm@festival-cannes.fr"}

	]
"cc":
	[
		{"hnlocher@free.fr"}
	]

Mais ça va être trop long à obtenir pour cette année.

Il y a une piste ici :

Sauvegarde des Emails

L'enregistrement des emails sans participants (TO et CC) et sans attachements d'assets fonctionne rapidement.

Par contre, lorsque l'on ajoute des collections en liaison oneToMany, l'enregistrement ne se fait pas avec la configuration actuelle, ou l'on reprend le champ clef étrangère.

La clef étrangère n'est pas initialisée au moment de l'écriture, et l'écriture échoue. Au moins, la cascade fonctionne.

En rendant la liaison bidirectionnelle (ce qui est idiot pour les participants, qui sont clairement en composition), la sauvegarde fonctionne.

Mise en oeuvre dans kdmMailFetcher

Tout fonctionne au moment des tests, mais lors de l'enregistrement du mail depuis kdmMailFetcher il se passe la chose suivante :

2019-04-28 09:32:10.916  INFO 3772 --- [           main] logFonctionnel                           :                   Email from : hnlocher@cst.fr
>>>                       Id : 12
>>>                  Subject : Fwd: Insider with enclosings
>>>                     Date : 2019.04.15 21.53.02
>>>                       To : devkdm@festival-cannes.fr
>>>                       Cc :
>>>                      Bcc :
>>> Nombre de pièces jointes : 1
>>>                    X-UID : null
>>>               Message-ID : <0f7971ed97aef73c5c8ec91fa9d1fb9b@cst.fr>
>>>          Is an autoreply :no
2019-04-28 09:32:10.947 DEBUG 3772 --- [           main] o.h.SQL                                  :
    insert
    into
        email
        (emailaccount, uid, emldirpath, emlfilename, sender, senddate, subject)
    values
        (?, ?, ?, ?, ?, ?, ?)
Hibernate:
    insert
    into
        email
        (emailaccount, uid, emldirpath, emlfilename, sender, senddate, subject)
    values
        (?, ?, ?, ?, ?, ?, ?)
2019-04-28 09:32:10.947 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [1] as [VARCHAR] - [TODO]
2019-04-28 09:32:10.947 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [2] as [VARCHAR] - [<0f7971ed97aef73c5c8ec91fa9d1fb9b@cst.fr>]
2019-04-28 09:32:10.947 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [3] as [VARCHAR] - [/to/do/]
2019-04-28 09:32:10.947 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [4] as [VARCHAR] - [todo.txt]
2019-04-28 09:32:10.947 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [5] as [VARCHAR] - [hnlocher@cst.fr]
2019-04-28 09:32:10.947 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [6] as [TIMESTAMP] - [Mon Apr 15 21:53:02 CEST 2019]
2019-04-28 09:32:10.947 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [7] as [VARCHAR] - [Fwd: Insider with enclosings]
2019-04-28 09:32:10.963 DEBUG 3772 --- [           main] o.h.SQL                                  :
    insert
    into
        emailassetpresence
        (email_idemail, assetuuid, assetkind, creationtime, filename, path)
    values
        (?, ?, ?, ?, ?, ?)
Hibernate:
    insert
    into
        emailassetpresence
        (email_idemail, assetuuid, assetkind, creationtime, filename, path)
    values
        (?, ?, ?, ?, ?, ?)
2019-04-28 09:32:10.963 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [1] as [INTEGER] - [25]
2019-04-28 09:32:10.963 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [2] as [VARCHAR] - [urn:uuid:2e564f38-3f0f-4f7a-a0fb-3786af07d8a3]
2019-04-28 09:32:10.963 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [3] as [VARCHAR] - [KDM]
2019-04-28 09:32:10.963 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [4] as [TIMESTAMP] - [null]
2019-04-28 09:32:10.963 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [5] as [VARCHAR] - [null]
2019-04-28 09:32:10.963 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [6] as [VARCHAR] - [null]
2019-04-28 09:32:10.963 DEBUG 3772 --- [           main] o.h.SQL                                  :
    insert
    into
        emailassetpresence
        (email_idemail, assetuuid, assetkind, creationtime, filename, path)
    values
        (?, ?, ?, ?, ?, ?)
Hibernate:
    insert
    into
        emailassetpresence
        (email_idemail, assetuuid, assetkind, creationtime, filename, path)
    values
        (?, ?, ?, ?, ?, ?)
2019-04-28 09:32:10.963 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [1] as [INTEGER] - [25]
2019-04-28 09:32:10.963 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [2] as [VARCHAR] - [urn:uuid:408139f6-70ab-4ed8-9fd1-c63ce1dc0d30]
2019-04-28 09:32:10.963 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [3] as [VARCHAR] - [CPL]
2019-04-28 09:32:10.963 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [4] as [TIMESTAMP] - [null]
2019-04-28 09:32:10.963 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [5] as [VARCHAR] - [null]
2019-04-28 09:32:10.963 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [6] as [VARCHAR] - [null]
2019-04-28 09:32:10.963 DEBUG 3772 --- [           main] o.h.SQL                                  :
    insert
    into
        emailparticipant
        (relation, email_idemail, adress)
    values
        (?, ?, ?)
Hibernate:
    insert
    into
        emailparticipant
        (relation, email_idemail, adress)
    values
        (?, ?, ?)
2019-04-28 09:32:10.979 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [1] as [VARCHAR] - [TO]
2019-04-28 09:32:10.979 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [2] as [INTEGER] - [25]
2019-04-28 09:32:10.979 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [3] as [VARCHAR] - [devkdm@festival-cannes.fr]
2019-04-28 09:32:10.979 DEBUG 3772 --- [           main] o.h.SQL                                  :
    insert
    into
        emailparticipant
        (relation, email_idemail, adress)
    values
        (?, ?, ?)
Hibernate:
    insert
    into
        emailparticipant
        (relation, email_idemail, adress)
    values
        (?, ?, ?)
2019-04-28 09:32:10.979 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [1] as [VARCHAR] - [CC]
2019-04-28 09:32:10.979 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [2] as [INTEGER] - [25]
2019-04-28 09:32:10.979 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [3] as [VARCHAR] - [devkdm@festival-cannes.fr]
2019-04-28 09:32:10.994 DEBUG 3772 --- [           main] o.h.SQL                                  :
    update
        emailassetpresence
    set
        email_idemail=?
    where
        email_idemail=?
        and assetuuid=?
        and assetkind=?
        and creationtime=?
        and filename=?
        and path=?
Hibernate:
    update
        emailassetpresence
    set
        email_idemail=?
    where
        email_idemail=?
        and assetuuid=?
        and assetkind=?
        and creationtime=?
        and filename=?
        and path=?
2019-04-28 09:32:10.994 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [1] as [INTEGER] - [25]
2019-04-28 09:32:10.994 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [2] as [INTEGER] - [25]
2019-04-28 09:32:10.994 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [3] as [VARCHAR] - [urn:uuid:2e564f38-3f0f-4f7a-a0fb-3786af07d8a3]
2019-04-28 09:32:10.994 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [4] as [VARCHAR] - [KDM]
2019-04-28 09:32:10.994 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [5] as [TIMESTAMP] - [null]
2019-04-28 09:32:10.994 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [6] as [VARCHAR] - [null]
2019-04-28 09:32:10.994 TRACE 3772 --- [           main] o.h.t.d.s.BasicBinder                    : binding parameter [7] as [VARCHAR] - [null]
2019-04-28 09:32:10.994 ERROR 3772 --- [           main] o.h.i.ExceptionMapperStandardImpl        : HHH000346: Error during managed flush [Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1]
2019-04-28 09:32:10.994  INFO 3772 --- [           main] o.h.e.j.b.i.AbstractBatchImpl            : HHH000010: On release of batch it still contained JDBC statements
2019-04-28 09:32:11.010 ERROR 3772 --- [           main] logTechnique                             : Erreur lors de l'appel au handler

org.springframework.orm.ObjectOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
	at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:338) ~[spring-orm-5.1.4.RELEASE.jar:5.1.4.RELEASE]
	at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:253) ~[spring-orm-5.1.4.RELEASE.jar:5.1.4.RELEASE]
	at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:536) ~[spring-orm-5.1.4.RELEASE.jar:5.1.4.RELEASE]
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:746) ~[spring-tx-5.1.4.RELEASE.jar:5.1.4.RELEASE]
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714) ~[spring-tx-5.1.4.RELEASE.jar:5.1.4.RELEASE]
	at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:533) ~[spring-tx-5.1.4.RELEASE.jar:5.1.4.RELEASE]
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:304) ~[spring-tx-5.1.4.RELEASE.jar:5.1.4.RELEASE]
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) ~[spring-tx-5.1.4.RELEASE.jar:5.1.4.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.4.RELEASE.jar:5.1.4.RELEASE]
	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-5.1.4.RELEASE.jar:5.1.4.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.4.RELEASE.jar:5.1.4.RELEASE]
	at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135) ~[spring-data-jpa-2.1.4.RELEASE.jar:2.1.4.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.4.RELEASE.jar:5.1.4.RELEASE]
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) ~[spring-aop-5.1.4.RELEASE.jar:5.1.4.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.4.RELEASE.jar:5.1.4.RELEASE]
	at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.4.RELEASE.jar:5.1.4.RELEASE]
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.1.4.RELEASE.jar:5.1.4.RELEASE]
	at com.sun.proxy.$Proxy123.save(Unknown Source) ~[?:?]
	at fr.cst.rd.digitalCinemaAssetHandler.services.EmailService.saveEmail(EmailService.java:31) ~[digitalCinemaAssetHandler-0.0.20-SNAPSHOT.jar:0.0.20-SNAPSHOT]
	at fr.cst.rd.kdmmailfetcher.db.SerialisationAssets.terminate(SerialisationAssets.java:226) ~[classes/:?]
	at fr.cst.rd.kdmmailfetcher.DigitalCinemaFileHandler.terminate(DigitalCinemaFileHandler.java:638) ~[classes/:?]
	at fr.cst.rd.kdmmailfetcher.DigitalCinemaEmailHandler.handleEmail(DigitalCinemaEmailHandler.java:66) ~[classes/:?]
	at fr.cst.rd.kdmmailfetcher.MailBox$UnreadMails.processFetchedMails(MailBox.java:66) [classes/:?]
	at fr.cst.rd.kdmmailfetcher.KdmMailFetcherJob.doJob(KdmMailFetcherJob.java:100) [classes/:?]
	at fr.cst.rd.kdmmailfetcher.KdmMailFetcher.run(KdmMailFetcher.java:59) [classes/:?]
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:813) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
	at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:797) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:324) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
	at fr.cst.rd.kdmmailfetcher.KdmMailFetcher.main(KdmMailFetcher.java:37) [classes/:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_121]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_121]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_121]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_121]
	at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run(AbstractRunMojo.java:558) [spring-boot-maven-plugin-2.1.2.RELEASE.jar:2.1.2.RELEASE]
	at java.lang.Thread.run(Thread.java:745) [?:1.8.0_121]
Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
	at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:67) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:54) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:46) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1340) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.persister.collection.OneToManyPersister.recreate(OneToManyPersister.java:186) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.action.internal.CollectionRecreateAction.execute(CollectionRecreateAction.java:50) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1454) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:511) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3283) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2479) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:473) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:178) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:39) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:271) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:98) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:532) ~[spring-orm-5.1.4.RELEASE.jar:5.1.4.RELEASE]
	... 35 more

L'assset urn:uuid:2e564f38-3f0f-4f7a-a0fb-3786af07d8a3 à déjà été écrite, il y a un update de fait dessus. Pourquoi ?

Réponse, c'était l'autre bout le la liaison qui écrit à son tour.

Il faut mettre @JoinColumn(... insertable="false", updatetable="false") du coté opposé.

Other références