AbstractMethodError in Java

1. Panoramica

A volte, possiamo incontrare AbstractMethodError in fase di esecuzione nella nostra applicazione. Se non conosciamo bene questo errore, potrebbe essere necessario del tempo per determinare la causa del problema.

In questo tutorial, daremo uno sguardo più da vicino a AbstractMethodError . Capiremo cos'è AbstractMethodError e quando può accadere.

2. Introduzione a AbstractMethodError

AbstractMethodError viene generato quando un'applicazione tenta di chiamare un metodo astratto non implementato.

Sappiamo che se ci sono metodi astratti non implementati, il compilatore si lamenterà per primo. Pertanto, l'applicazione non verrà creata affatto.

Potremmo chiedere come possiamo ottenere questo errore in fase di esecuzione?

Per prima cosa, diamo un'occhiata a dove AbstractMethodError si inserisce nella gerarchia delle eccezioni Java:

java.lang.Object |_java.lang.Throwable |_java.lang.Error |_java.lang.LinkageError |_java.lang.IncompatibleClassChangeError |_java.lang.AbstractMethodError

Come mostra la gerarchia sopra, questo errore è una sottoclasse di IncompatibleClassChangeError . Come suggerisce il nome della sua classe genitore, AbstractMethodError viene solitamente lanciato quando esistono incompatibilità tra classi compilate o file JAR.

Successivamente, capiamo come può verificarsi questo errore.

3. Come può verificarsi questo errore

Quando creiamo un'applicazione, di solito importiamo alcune librerie per semplificare il nostro lavoro.

Diciamo che nella nostra applicazione includiamo una libreria baeldung-queue . La libreria baeldung-queue è una libreria con specifiche di alto livello, che contiene solo un'interfaccia:

public interface BaeldungQueue { void enqueue(Object o); Object dequeue(); } 

Inoltre, per utilizzare l' interfaccia BaeldungQueue , importiamo una libreria di implementazione BaeldungQueue : good-queue . La libreria good-queue ha anche una sola classe:

public class GoodQueue implements BaeldungQueue { @Override public void enqueue(Object o) { //implementation } @Override public Object dequeue() { //implementation } } 

Ora, se sia good-queue che baeldung-queue sono nel classpath, possiamo creare un'istanza BaeldungQueue nella nostra applicazione:

public class Application { BaeldungQueue queue = new GoodQueue(); public void someMethod(Object element) { queue.enqueue(element); // ... queue.dequeue(); // ... } } 

Fin qui tutto bene.

Un giorno, abbiamo appreso che baeldung-queue ha rilasciato la versione 2.0 e che viene fornito con un nuovo metodo:

public interface BaeldungQueue { void enqueue(Object o); Object dequeue(); int size(); } 

Vogliamo utilizzare il nuovo metodo size () nella nostra applicazione. Pertanto, aggiorniamo la libreria baeldung-queue da 1.0 a 2.0 . Tuttavia, ci dimentichiamo di controllare se esiste una nuova versione della libreria good-queue che implementa le modifiche all'interfaccia BaeldungQueue .

Pertanto, abbiamo good-queue 1.0 e baeldung-queue 2.0 nel classpath.

Inoltre, iniziamo a utilizzare il nuovo metodo nella nostra applicazione:

public class Application { BaeldungQueue queue = new GoodQueue(); public void someMethod(Object element) { // ... int size = queue.size(); //<-- AbstractMethodError will be thrown // ... } } 

Il nostro codice verrà compilato senza alcun problema.

Tuttavia, quando la riga queue.size () viene eseguita in fase di esecuzione, verrà lanciata un'eccezione AbstractMethodError . Questo perché la libreria good-queue 1.0 non implementa il metodo size () nell'interfaccia BaeldungQueue .

4. Un esempio del mondo reale

Attraverso il semplice scenario BaeldungQueue e GoodQueue , possiamo avere l'idea di quando un'applicazione può lanciare AbstractMethodError.

In questa sezione vedremo un esempio pratico di AbstractMethodError .

java.sql.Connection è un'interfaccia importante nell'API JDBC. Dalla versione 1.7, sono stati aggiunti diversi nuovi metodi all'interfaccia Connection , come getSchema ().

Il database H2 è un database SQL open source piuttosto veloce. Dalla versione 1.4.192 , ha aggiunto il supporto del metodo java.sql.Connection.getSchema () . Tuttavia, nelle versioni precedenti, il database H2 non ha ancora implementato questo metodo.

Successivamente, chiameremo il metodo java.sql.Connection.getSchema () da un'applicazione Java 8 su un database H2 precedente versione 1.4.191 . Vediamo cosa succederà.

Creiamo una classe di unit-test per verificare se la chiamata al metodo Connection.getSchema () genererà AbstractMethodError :

class AbstractMethodErrorUnitTest { private static final String url = "jdbc:h2:mem:A-DATABASE;INIT=CREATE SCHEMA IF NOT EXISTS myschema"; private static final String username = "sa"; @Test void givenOldH2Database_whenCallgetSchemaMethod_thenThrowAbstractMethodError() throws SQLException { Connection conn = DriverManager.getConnection(url, username, ""); assertNotNull(conn); Assertions.assertThrows(AbstractMethodError.class, () -> conn.getSchema()); } } 

Se eseguiamo il test, passerà, confermando che la chiamata a getSchema () genera AbstractMethodError .

5. conclusione

A volte possiamo vedere AbstractMethodError in fase di esecuzione. In questo articolo, abbiamo discusso quando l'errore si verifica attraverso esempi.

Quando aggiorniamo una libreria della nostra applicazione, è sempre buona norma verificare se altre dipendenze stanno utilizzando la libreria e considerare l'aggiornamento delle dipendenze correlate.

D'altra parte, una volta che affrontiamo AbstractMethodError , con una buona comprensione di questo errore, possiamo risolvere il problema rapidamente.

Come sempre, il codice sorgente completo dell'articolo è disponibile su GitHub.