Migración Java EE

Migración de Java EE a Jakarta EE

Evolución de aplicaciones Java EE hacia Jakarta EE, abordando compatibilidad, dependencias y cambios necesarios para mantener la aplicación preparada para nuevas versiones del ecosistema.

Pedir diagnóstico gratuito

El reto

Una migración empresarial requiere algo más que cambiar paquetes

Las aplicaciones Java EE existentes pueden acumular dependencias, APIs antiguas, servidores de aplicaciones y componentes que condicionan su evolución. Analizar estos elementos antes de migrar permite identificar impactos técnicos y definir una estrategia adecuada para cada aplicación.

El cambio de espacio de nombres de javax.* a jakarta.* es mecánico en el código propio. Lo que marca el ritmo real de la migración son las dependencias de terceros: hasta que todas publican una versión compatible, el plan depende de ellas y no del equipo.

Qué se analiza

Qué se revisa antes de cambiar el espacio de nombres

  • Análisis de aplicaciones Java EE existentes
  • Identificación de APIs y dependencias afectadas
  • Migración de javax.* a jakarta.*
  • Compatibilidad con versiones modernas del servidor
  • Revisión de configuraciones y librerías
  • Adaptación de componentes empresariales
  • Validación de integraciones existentes

Tecnologías relacionadas

El ecosistema afectado por el salto a Jakarta EE

  • Java EE
  • Jakarta EE
  • JPA
  • JAX-RS
  • JAX-WS
  • Hibernate
  • WildFly
  • JBoss
  • Maven

Por qué cambió el espacio de nombres y qué implica

El cambio de javax a jakarta no fue una mejora técnica: fue una consecuencia legal, y por eso es tan radical.

Cuando la gestión de Java EE pasó a la Eclipse Foundation, la marca Java se quedó donde estaba. La primera entrega, Jakarta EE 8, era idéntica a Java EE 8 y mantenía javax.*. Jakarta EE 9 hizo el corte: renombró todos los paquetes a jakarta.* sin añadir una sola funcionalidad nueva. Es una versión que existe solo para que el ecosistema pueda cruzar el puente.

Eso tiene una consecuencia práctica incómoda: no hay compatibilidad hacia atrás y no hay término medio. Una aplicación no puede estar medio migrada, porque el contenedor carga un espacio de nombres o el otro. Las dos variantes de la misma librería en el classpath no se complementan, se estorban.

En el código propio el cambio es mecánico y lo resuelve una herramienta. Lo que marca el calendario son las dependencias de terceros que aún no publican una variante jakarta, y los descriptores XML, que también cambian de espacio de nombres y suelen olvidarse hasta que el despliegue falla. Casi siempre viene acompañado de una subida de versión de Java, porque los servidores que soportan Jakarta EE ya no certifican Java 8.

Qué versión de Jakarta EE corresponde a cada servidor

La versión de destino no se elige por preferencia: la fija el servidor que se pueda desplegar en producción.

Versiones de Jakarta EE, espacio de nombres y requisitos
VersiónEspacio de nombresJava mínimoServidores habituales
Java EE 8 / Jakarta EE 8javaxJava 8WildFly 18-26, Tomcat 9, Payara 5, JBoss EAP 7.x
Jakarta EE 9 y 9.1jakartaJava 8 (9) y Java 11 (9.1)Tomcat 10.0, WildFly con perfil preview
Jakarta EE 10jakartaJava 11WildFly 27 y posteriores, Tomcat 10.1, Payara 6, JBoss EAP 8
Jakarta EE 11jakartaJava 17Tomcat 11 y versiones recientes de WildFly y Payara

Cada fabricante publica su propia matriz de certificación y la revisa en cada versión menor. Esta tabla sirve para acotar el terreno; la decisión final se toma contra la matriz oficial del servidor concreto que esté en producción.

Los descriptores XML que también hay que cambiar

Es la parte que más se olvida, porque el código compila sin ella y el fallo solo aparece al desplegar.

Versión y espacio de nombres de cada descriptor antes y después
DescriptorJava EE 8Jakarta EE 9Jakarta EE 10
persistence.xml2.23.03.1
web.xml4.05.06.0
beans.xml2.03.04.0
faces-config.xml2.33.04.0
ejb-jar.xml3.24.04.0

Además del número de versión cambia el propio espacio de nombres del XML, que pasa a apuntar a jakarta.ee/xml/ns/jakartaee. Un descriptor con la versión nueva y el espacio de nombres viejo falla en el arranque, no en la compilación.

Errores típicos y qué los provoca en realidad

package javax.persistence does not exist

Causa: El proyecto ya usa una dependencia jakarta, pero quedan importaciones sin convertir. Suele pasar en módulos que la herramienta de migración no recorrió.

Qué se hace: Convertir el módulo entero, no fichero a fichero, y comprobar después que no quede ninguna referencia a javax en las clases de persistencia.

ClassNotFoundException: javax.servlet.http.HttpServlet

Causa: El artefacto se despliega en un contenedor que ya solo expone el espacio de nombres jakarta, y el código compilado sigue pidiendo el antiguo.

Qué se hace: Comprobar la versión del servidor antes que el código: Tomcat 9 sirve javax y Tomcat 10 sirve jakarta. No es un error de la aplicación, es un desajuste de destino.

NoSuchMethodError en una librería tras convertir los paquetes

Causa: Conviven las dos variantes de la misma dependencia, la javax y la jakarta, y el cargador de clases resuelve hacia la que no toca.

Qué se hace: Revisar el árbol con mvn dependency:tree y excluir de forma explícita las transitivas que arrastran la variante antigua. Es el fallo más frecuente y el que más tiempo consume.

HV000183: Unable to initialize jakarta.el.ExpressionFactory

Causa: Hibernate Validator necesita una implementación de Expression Language, y al migrar se queda la versión javax que ya no encaja.

Qué se hace: Añadir la implementación jakarta.el correspondiente a la versión de Jakarta EE de destino. Aparece en aplicaciones que validan fuera de un contenedor completo.

Cómo se aborda la migración sin bloquear el desarrollo

  1. Inventario de dependencias, primero

    Para cada dependencia: si existe versión jakarta, cuál es, y si no existe, qué la sustituye. Este documento es el que decide si la migración dura semanas o meses, y es lo primero que se entrega.

  2. Elegir el servidor de destino

    Condiciona la versión de Jakarta EE y la de Java. Si el servidor de producción no se puede mover todavía, el destino se ajusta a lo que ese servidor certifique, no al revés.

  3. Automatizar la conversión de código

    Eclipse Transformer y las recetas de OpenRewrite hacen el renombrado de forma acotada, solo sobre los paquetes que pertenecen a Jakarta EE. Un buscar y reemplazar sobre todo el proyecto acaba tocando cadenas de texto y nombres propios que no debía.

  4. Convertir los descriptores a mano

    Son pocos ficheros y las herramientas no siempre los cubren del todo. Versión y espacio de nombres a la vez, en el mismo commit que el código del módulo al que pertenecen.

  5. Desplegar por fases, con pruebas en cada una

    Cada fase deja la aplicación funcionando y desplegada. Mantener una rama de migración abierta durante meses acaba en un conflicto que nadie se atreve a resolver.

Preguntas frecuentes

Dudas frecuentes sobre el cambio a Jakarta EE

¿Se puede migrar a Jakarta EE sin parar el desarrollo?

Normalmente sí. El cambio de javax a jakarta es mecánico en el código propio; lo que marca el ritmo son las dependencias de terceros que todavía no han publicado una versión compatible. Ese inventario es lo primero que se hace, porque es lo que decide si la migración dura semanas o meses.

¿Se puede migrar solo una parte de la aplicación?

No dentro del mismo despliegue. El contenedor expone un espacio de nombres o el otro, así que el artefacto se convierte entero. Lo que sí se puede es trocear la aplicación en varios desplegables y migrarlos por separado, si la arquitectura lo permite.

¿Basta con buscar y reemplazar javax por jakarta?

No, y hacerlo suele romper cosas. Hay paquetes javax que no pertenecen a Jakarta EE y siguen en el JDK, como javax.sql o javax.naming. Las herramientas específicas acotan el renombrado a lo que de verdad cambió de dueño.

¿Qué pasa con Hibernate al pasar a jakarta.persistence?

Hibernate 6 es el que trae el cambio de espacio de nombres, y además reescribió el motor de consultas: HQL que antes funcionaba puede comportarse de otra manera. Se aborda comparando el SQL generado antes y después sobre las consultas críticas, no confiando en que compile.

¿Hay que ir a la última versión de Jakarta EE?

No necesariamente. Lo razonable suele ser ir a la versión más alta que certifique el servidor que podéis desplegar hoy. Saltar a la última y descubrir después que el servidor no la soporta obliga a dos migraciones en lugar de una.

¿Y si una dependencia crítica no tiene versión jakarta?

Hay tres salidas: sustituirla, transformar el artefacto con Eclipse Transformer, o aislar su uso tras una interfaz propia y posponer la decisión. La elección depende de cuánto código dependa de ella, y es una de las cosas que el inventario deja cerradas antes de empezar.

¿Tienes este reto?

¿Tenéis una aplicación Java EE que hay que mover?

Cuéntame qué servidor usáis y qué dependencias os preocupan. El inventario de compatibilidad es lo primero que se hace, y es lo que dice si esto son semanas o meses.

Pedir diagnóstico gratuito

Llamada de 30 minutos, sin coste. Respondo en menos de 48 horas.

En la llamada: versión de Java, framework, servidor y qué duele hoy. Si no puedo ayudarte, te lo digo. Qué incluye el diagnóstico