title: JUnit, @ControllerAdvice and lack of checked exceptions in Kotlin
body: <p>I wrote a <a href="http://www.mkyong.com/spring3/spring-aop-aspectj-annotation-example/" rel="nofollow noreferrer">validation advisor</a> in Kotlin which throws <code>EntityValidationException</code> when validation fails:</p>
  
  <pre><code>@Aspect
  @Named
  class ValidationAdvisor
  @Inject constructor(val validator: EntityValidator) {
      @Around(EVERY_SAVE_AND_UPDATE_TO_DATABASE)
      fun validate(point: ProceedingJoinPoint): Any {
          val result: List&lt;ConstraintViolation&lt;Any&gt;&gt; = validator.validate(getEntity(point))
          if (isEntityValid(result))
              return point.proceed()
  
          throw EntityValidationException(
              violationInfos = result as List&lt;ConstraintViolationInfo&gt;
          )
      }
  
      private fun getEntity(point: ProceedingJoinPoint): Any {
          return point.args[0]
      }
  
      private fun isEntityValid(result: List&lt;ConstraintViolation&lt;Any&gt;&gt;): Boolean {
          return result.isEmpty()
      }
  
      companion object {
          const val EVERY_SAVE_AND_UPDATE_TO_DATABASE = "execution(* beans.repositories.BaseRepository.save(..))"
      }
  }
  </code></pre>
  
  <p>I have a JUnit test (I write some parts in Kotlin and some in Java, to learn Kotlin in existing private project) which checks if exception is thrown:</p>
  
  <pre><code>@Test(expected = EntityValidationException.class)
  public void test_WhenNameIsNotPresent_ThenExceptionIsThrown() throws Exception {
      repository.save(/* entity to save */);
  }
  </code></pre>
  
  <p>But then I saw that test fails because it throws <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/UndeclaredThrowableException.html" rel="nofollow noreferrer">UndeclaredThrowableException</a> instead of <code>EntityValidationException</code>. Next, I read that <a href="https://kotlinlang.org/docs/reference/exceptions.html#checked-exceptions" rel="nofollow noreferrer" title="Kotlin does not have checked exception">Kotlin does not have checked exception</a>. I think not only me have this problem - I am pretty sure that <a href="https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc#global-exception-handling" rel="nofollow noreferrer" title="Spring handling exceptions with @ControllerAdvice">way of handling exceptions with @ControllerAdvice in Spring and Java</a> also may be problematic when we decide to switch to Kotlin in production projects - because it rely on class which is thrown, and throwing <code>UndeclaredThrowableException</code> take away from us this possibility. Is there a way to by-pass this behaviour, to make sure that is possible to switch to Kotlin and <em>old</em> Spring way of handling exceptions (and unit tests for <code>ValidationAdvisor</code>) will remain unchanged? Thank you in advance for any help.</p>
  
  <p><strong>P.S.</strong> Github repo for project is available here: <a href="https://github.com/radek-anuszewski/film-site" rel="nofollow noreferrer">Playgroud for Kotlin, Spring Data etc.</a>.</p>
  
  <p><strong>P.S.2</strong> Stacktrace:</p>
  
  <pre><code>at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
      at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
      at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
      at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
      at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237)
      at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
      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:497)
      at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
  Caused by: java.lang.reflect.UndeclaredThrowableException
      at com.sun.proxy.$Proxy65.save(Unknown Source)
      at ActorValidationTest.test_WhenNameIsNotPresent_ThenExceptionIsThrown(ActorValidationTest.java:26)
      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:497)
      at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
      at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
      at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
      at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
      at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:19)
      ... 26 more
  Caused by: beans.validator.exceptions.EntityValidationException
      at beans.aop.validation.ValidationAdvisor.validate(ValidationAdvisor.kt:23)
      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:497)
      at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:629)
      at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:618)
      at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
      at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
      at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
      ... 37 more
  </code></pre>
  
  <p>For me looks like <code>EntityValidationException</code> (which I want to be thrown) causes <code>UndeclaredThrowableException</code>.
  <code>EntityValidationException</code> Kotlin class code:</p>
  
  <pre><code>package beans.validator.exceptions
  
  import beans.validator.constraintViolation.ConstraintViolationInfo
  
  class EntityValidationException (val violationInfos: List&lt;ConstraintViolationInfo&gt;) : Exception() {
  }
  </code></pre>
  
  <p><strong>P.S.3</strong> This also didn't work:</p>
  
  <pre><code>@Around(EVERY_SAVE_AND_UPDATE_TO_DATABASE)
  @Throws(EntityValidationException::class)
  fun validate(point: ProceedingJoinPoint): Any /* rest of code*/
  </code></pre>
  
  <p><strong>P.S.4</strong> Maybe the problem is that <code>@Aspect</code> is <code>@Around</code> Spring Data repository?</p>
  
  <pre><code>companion object {
          const val EVERY_SAVE_AND_UPDATE_TO_DATABASE = "execution(* beans.repositories.BaseRepository.save(..))"
      }
  ....
  @NoRepositoryBean
  public interface BaseRepository&lt;ENTITY, IDENTIFIER extends Serializable&gt;
          extends JpaRepository&lt;ENTITY, IDENTIFIER&gt;, JpaSpecificationExecutor&lt;ENTITY&gt; {
  }
  </code></pre>