From cf4d45befbbbc1de7544bf99a8b6f6a4560c5a70 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Mon, 20 May 2019 14:37:03 +0200 Subject: [PATCH] refactor: unwrap invocationTargetException (#1718) --- .../deploy/BeanLifecycleAdapterFactory.java | 20 ++- .../lifecycle/TestLifecycleExceptions.java | 47 +++++++ .../basic/EBasicWithLifecycleExceptions.java | 130 ++++++++++++++++++ 3 files changed, 194 insertions(+), 3 deletions(-) create mode 100644 src/test/java/org/tests/lifecycle/TestLifecycleExceptions.java create mode 100644 src/test/java/org/tests/model/basic/EBasicWithLifecycleExceptions.java diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanLifecycleAdapterFactory.java b/src/main/java/io/ebeaninternal/server/deploy/BeanLifecycleAdapterFactory.java index f9bdcd224..0d525bb81 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanLifecycleAdapterFactory.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanLifecycleAdapterFactory.java @@ -145,6 +145,20 @@ class BeanLifecycleAdapterFactory { return methodList.toArray(new Method[methodList.size()]); } + static RuntimeException unwrapException(ReflectiveOperationException e) { + if (e instanceof InvocationTargetException) { + Throwable targetException = ((InvocationTargetException)e).getTargetException(); + if (targetException instanceof RuntimeException) { + // return unchecked exceptions + return (RuntimeException) targetException; + } else { + // wrap checked exceptions + return new PersistenceException("Error invoking lifecycle method", targetException); + } + } + return new PersistenceException("Error invoking lifecycle method", e); + } + /** * Holds Methods for the lifecycle events.s */ @@ -192,7 +206,7 @@ class BeanLifecycleAdapterFactory { try { method.invoke(bean); } catch (InvocationTargetException | IllegalAccessException e) { - throw new PersistenceException("Error invoking lifecycle method", e); + throw unwrapException(e); } } @@ -268,7 +282,7 @@ class BeanLifecycleAdapterFactory { try { method.invoke(bean); } catch (InvocationTargetException | IllegalAccessException e) { - throw new PersistenceException("Error invoking lifecycle method", e); + throw unwrapException(e); } } @@ -301,7 +315,7 @@ class BeanLifecycleAdapterFactory { try { method.invoke(bean); } catch (InvocationTargetException | IllegalAccessException e) { - throw new PersistenceException("Error invoking lifecycle method", e); + throw unwrapException(e); } } diff --git a/src/test/java/org/tests/lifecycle/TestLifecycleExceptions.java b/src/test/java/org/tests/lifecycle/TestLifecycleExceptions.java new file mode 100644 index 000000000..3e5ddf4a3 --- /dev/null +++ b/src/test/java/org/tests/lifecycle/TestLifecycleExceptions.java @@ -0,0 +1,47 @@ +package org.tests.lifecycle; + +import io.ebean.BaseTestCase; +import io.ebean.DB; +import org.tests.model.basic.EBasicWithLifecycleExceptions; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.io.IOException; + +import javax.persistence.PersistenceException; + +public class TestLifecycleExceptions extends BaseTestCase { + + @Test + public void prePersist_unchecked() { + EBasicWithLifecycleExceptions bean = new EBasicWithLifecycleExceptions(); + bean.preException = new IndexOutOfBoundsException(); + assertThatThrownBy(() -> DB.save(bean)).isInstanceOf(IndexOutOfBoundsException.class); + } + + @Test + public void prepersist_checked() { + EBasicWithLifecycleExceptions bean = new EBasicWithLifecycleExceptions(); + bean.preException = new IOException(); + assertThatThrownBy(() -> DB.save(bean)) + .isInstanceOf(PersistenceException.class) + .hasCauseInstanceOf(IOException.class); + } + + @Test + public void postPersist_unchecked() { + EBasicWithLifecycleExceptions bean = new EBasicWithLifecycleExceptions(); + bean.postException = new IndexOutOfBoundsException(); + assertThatThrownBy(() -> DB.save(bean)).isInstanceOf(IndexOutOfBoundsException.class); + } + + @Test + public void postpersist_checked() { + EBasicWithLifecycleExceptions bean = new EBasicWithLifecycleExceptions(); + bean.postException = new IOException(); + assertThatThrownBy(() -> DB.save(bean)) + .isInstanceOf(PersistenceException.class) + .hasCauseInstanceOf(IOException.class); + } +} diff --git a/src/test/java/org/tests/model/basic/EBasicWithLifecycleExceptions.java b/src/test/java/org/tests/model/basic/EBasicWithLifecycleExceptions.java new file mode 100644 index 000000000..76c1f00f0 --- /dev/null +++ b/src/test/java/org/tests/model/basic/EBasicWithLifecycleExceptions.java @@ -0,0 +1,130 @@ +package org.tests.model.basic; + +import io.ebean.annotation.PostSoftDelete; +import io.ebean.annotation.PreSoftDelete; +import io.ebean.annotation.SoftDelete; + +import javax.annotation.PostConstruct; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.PostLoad; +import javax.persistence.PostPersist; +import javax.persistence.PostRemove; +import javax.persistence.PostUpdate; +import javax.persistence.PrePersist; +import javax.persistence.PreRemove; +import javax.persistence.PreUpdate; +import javax.persistence.Table; +import javax.persistence.Version; + +@Entity +@Table(name = "e_basic_with_ex") +public class EBasicWithLifecycleExceptions { + + @Id + Long id; + + @SoftDelete + boolean deleted; + + @Version + Long version; + + public transient Throwable preException; + public transient Throwable postException; + + @PrePersist + public void prePersist() throws Throwable { + if (preException != null) { + throw preException; + } + } + + @PostPersist + public void postPersist() throws Throwable { + if (postException != null) { + throw postException; + } + } + + @PreUpdate + public void preUpdate() throws Throwable { + if (preException != null) { + throw preException; + } + } + + @PostUpdate + public void postUpdate() throws Throwable { + if (postException != null) { + throw postException; + } + } + + @PreRemove + public void preRemove() throws Throwable { + if (preException != null) { + throw preException; + } + } + + @PostRemove + public void postRemove() throws Throwable { + if (postException != null) { + throw postException; + } + } + + @PreSoftDelete + public void preSoftDelete() throws Throwable { + if (preException != null) { + throw preException; + } + } + + @PostSoftDelete + public void postSoftDelete() throws Throwable { + if (postException != null) { + throw postException; + } + } + + @PostLoad + public void postLoad1() throws Throwable { + if (postException != null) { + throw postException; + } + } + + @PostConstruct + public void postConstruct1() throws Throwable { + if (postException != null) { + throw postException; + } + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public boolean isDeleted() { + return deleted; + } + + public void setDeleted(boolean deleted) { + this.deleted = deleted; + } + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } + +}