Wanneer gooit Java UndeclaredThrowableException?

Java Top

Ik heb zojuist het nieuwe aangekondigd Leer de lente natuurlijk, gericht op de basisprincipes van Spring 5 en Spring Boot 2:

>> BEKIJK DE CURSUS

1. Overzicht

In deze zelfstudie gaan we zien waardoor Java een instantie van het UndeclaredThrowableException uitzondering.

Eerst beginnen we met een stukje theorie. Vervolgens zullen we proberen de aard van deze uitzondering beter te begrijpen aan de hand van twee praktijkvoorbeelden.

2. Het UndeclaredThrowableException

Theoretisch gesproken zal Java een instantie van UndeclaredThrowableException wanneer we proberen een niet-aangegeven gecontroleerde uitzondering te genereren. Dat wil zeggen, we hebben de gecontroleerde uitzondering niet aangegeven in het gooit clausule, maar we gooien die uitzondering in de body van de methode.

Je zou kunnen zeggen dat dit onmogelijk is omdat de Java-compiler dit voorkomt met een compilatiefout. Als we bijvoorbeeld proberen te compileren:

public void undeclared () {throw nieuwe IOException (); }

De Java-compiler mislukt met het bericht:

java: niet-gerapporteerde uitzondering java.io.IOException; moet worden gevangen of verklaard te worden gegooid

Hoewel het gooien van niet-aangegeven gecontroleerde uitzonderingen tijdens het compileren misschien niet gebeurt, is het nog steeds een mogelijkheid tijdens runtime. Laten we bijvoorbeeld eens kijken naar een runtime-proxy die een methode onderschept die geen uitzonderingen genereert:

openbare leegte opslaan (Objectgegevens) {// weggelaten}

Als de proxy zelf een aangevinkte uitzondering genereert, vanuit het perspectief van de beller, de sparen methode gooit die gecontroleerde uitzondering. De beller weet waarschijnlijk niets van die proxy en zal de sparen voor deze uitzondering.

In dergelijke omstandigheden zal Java de feitelijk aangevinkte uitzondering in een UndeclaredThrowableException en gooi de UndeclaredThrowableException in plaats daarvan. Het is vermeldenswaard dat de UndeclaredThrowableException zelf is een ongecontroleerde uitzondering.

Nu we genoeg weten over de theorie, laten we eens kijken naar enkele praktijkvoorbeelden.

3. Java Dynamic Proxy

Laten we als eerste voorbeeld een runtime-proxy maken voor java.util.List interface en onderschep zijn methodeaanroepen. Ten eerste moeten we het InvocationHandler interface en zet de extra logica daar:

public class ExceptionalInvocationHandler implementeert InvocationHandler {@Override public Object invoke (Object proxy, Method method, Object [] args) gooit Throwable {if ("size" .equals (method.getName ())) {throw new SomeCheckedException ("Always failed" ); } gooi nieuwe RuntimeException (); }} public class SomeCheckedException breidt Uitzondering {public SomeCheckedException (String bericht) {super (bericht) uit; }}

Deze proxy genereert een aangevinkte uitzondering als de proxy-methode dat is grootte. Anders genereert het een ongecontroleerde uitzondering.

Laten we eens kijken hoe Java met beide situaties omgaat. Eerst bellen we het List.size () methode:

ClassLoader classLoader = getClass (). GetClassLoader (); InvocationHandler invocationHandler = nieuwe ExceptionalInvocationHandler (); Lijst proxy = (Lijst) Proxy.newProxyInstance (classLoader, nieuwe klasse [] {List.class}, invocationHandler); assertThatThrownBy (proxy :: grootte) .isInstanceOf (UndeclaredThrowableException.class) .hasCauseInstanceOf (SomeCheckedException.class);

Zoals hierboven weergegeven, maken we een proxy voor het Lijst interface en bel het grootte methode erop. De proxy onderschept op zijn beurt de oproep en genereert een gecontroleerde uitzondering. Vervolgens verpakt Java deze gecontroleerde uitzondering in een instantie van UndeclaredThrowableException.Dit gebeurt omdat we op de een of andere manier een gecontroleerde uitzondering gooien zonder deze in de methode-declaratie te declareren.

Als we een andere methode op het Lijst koppel:

assertThatThrownBy (proxy :: isEmpty) .isInstanceOf (RuntimeException.class);

Aangezien de proxy een ongecontroleerde uitzondering genereert, laat Java de uitzondering zich ongewijzigd doorgeven.

4. Lente-aspect

Hetzelfde gebeurt wanneer we een aangevinkte uitzondering in een Spring Aspect gooien terwijl de geadviseerde methoden ze niet declareren. Laten we beginnen met een annotatie:

@Target (ElementType.METHOD) @Retention (RetentionPolicy.RUNTIME) openbaar @interface ThrowUndeclared {}

Nu gaan we alle methoden adviseren die met deze annotatie zijn geannoteerd:

@Aspect @Component publieke klasse UndeclaredAspect {@Around ("@ annotation (undeclared)") publiek objectadvies (ProceedJoinPoint pjp, ThrowUndeclared undeclared) gooit Throwable {throw new SomeCheckedException ("AOP Checked Exception"); }}

In principe zorgt dit advies ervoor dat alle geannoteerde methoden een gecontroleerde uitzondering genereren, zelfs als ze een dergelijke uitzondering niet hebben gedeclareerd. Laten we nu een service maken:

@Service openbare klasse UndeclaredService {@ThrowUndeclared openbare ongeldige doSomething () {}}

Als we de geannoteerde methode aanroepen, genereert Java een instantie van UndeclaredThrowableException uitzondering:

@RunWith (SpringRunner.class) @SpringBootTest (klassen = UndeclaredApplication.class) openbare klasse UndeclaredThrowableExceptionIntegrationTest {@Autowired privé UndeclaredService-service; @Test openbare ongeldig gegevenAnAspect_whenCallingAdvisedMethod_thenShouldWrapTheException () {assertThatThrownBy (service :: doSomething) .isInstanceOf (UndeclaredThrowableException.class) .hasCauseInstanceOf (SomeCheckedException.class); }}

Zoals hierboven getoond, kapselt Java de feitelijke uitzondering in als oorzaak en gooit het UndeclaredThrowableException uitzondering.

5. Conclusie

In deze zelfstudie hebben we gezien waardoor Java een instantie van het UndeclaredThrowableException uitzondering.

Zoals gewoonlijk zijn alle voorbeelden beschikbaar op GitHub.

Java onderkant

Ik heb zojuist het nieuwe aangekondigd Leer de lente natuurlijk, gericht op de basisprincipes van Spring 5 en Spring Boot 2:

>> BEKIJK DE CURSUS