ClassCastException con oggetto in ClassLoader diversi
DOMANDA:
Perchè ricevo un errore di ClassCastException se dalla mia webapp recupero lo stesso oggetto creato da un'altra webapp?
RISPOSTA:
Di solito questo errore si verifica quando stiamo utilizzando un oggetto in due class loader diversi. Ad esempio ho una webapp A che utilizza un oggetto X del jar X.jar presente nella sua WEB-INF/lib. Decido di recuperare l'oggetto X dalla webapp B che avrà anch'essa nella sua WEB-INF/lib il jar X.jar.
In questo caso è vero che l'oggetto X è lo stesso ma viene caricato sia nel class loader di A che in quello di B. Ciò comporta la generazione di un errore di ClassCastException quando si tenta di recuperare l'oggetto X da B.
Per ovviare facilmente a questo errore si potrebbe decidere di inserire il jar X.jar in un class loader condiviso tra le due webapp A e B (ad esempio il class loader dell'Application Server).
Una soluzione più elegante, che offre una serie di vantaggi e rispetta le tecniche di Design Pattern, è quella di inserire a livello di class loader condiviso, solo una interfaccia e demandare l'implementazione di tale interfaccia alle classi che saranno caricate dai diversi class loader.
Vediamo un esempio:
N.B.
Per provare l'esempio, abilitare il crossContext nel file context.xml presente nella cartella config di tomcat
Per provare l'esempio, abilitare il crossContext nel file context.xml presente nella cartella config di tomcat
<context crosscontext="true">
...
</context>
Definizione dell'interfaccia ICar contenuta nel jar Interfaces.jar
package interfaces; public interface ICar { public void setNome(String nome); public String getNome(); public void setModello(String modello); public String getModello(); }
Definizione della classe BMWCar (che implementa ICar) contenuta nel jar Pojo.jar
import interfaces.ICar; public class BMWCar implements ICar{ private String nome; private String modello; public void setNome(String nome) { this.nome=nome; } public String getNome(){ return this.nome; } public void setModello(String modello){ this.modello=modello; } public String getModello(){ return this.modello; } }
Servlet CreateCar della webapp A:
- crea un oggetto bmw di tipo BMWCar utilizzando l'interfaccia ICar
- memorizza l'oggetto bmw nell'Application Scope con chiave CAR
import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import interfaces.ICar; import pojo.BMWCar; @WebServlet("/CreateBMWCar") public class CreateBMWCar extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext sc = request.getServletContext(); ICar bmw = new BMWCar(); bmw.setModello("Serie 3"); bmw.setNome("320d"); sc.setAttribute("CAR", bmw); response.setContentType("text/plain"); PrintWriter out = response.getWriter(); out.write("Creata auto:\n"); out.write("Nome: "+bmw.getNome() + "Modello: "+bmw.getModello() ); } }
Servlet ReadCar della WebApp B: recupera dall'Application Scope della webapp A l'auto creata:
import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import interfaces.ICar; @WebServlet("/ReadCar") public class ReadCar extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext sc = request.getServletContext().getContext("/WebAppA"); ICar car = (ICar) sc.getAttribute("CAR"); response.setContentType("text/plain"); PrintWriter out = response.getWriter(); out.write("Auto recuperata:\n"); out.write("Nome: "+car.getNome() + " Modello: "+car.getModello()+"" ); } }
Di seguito un'immagine per capire come e dove sono organizzate/definite le classi descritte
Commenti
Posta un commento