Bloque III · Tema 5 · Cuerpo de Técnicos Auxiliares de Informática
Así lo numera la convocatoria: Bloque III. Desarrollo de sistemas. En nuestro temario es el tema 19 de 33.
Arquitectura Java EE/Jakarta EE y plataforma.NET: componentes, persistencia y seguridad. Características, elementos, lenguajes y funciones en ambos entornos. Desarrollo de interfaces.
Las dos plataformas empresariales, puestas una al lado de la otra pieza por pieza, que es como las pregunta el tribunal: la máquina virtual frente al CLR, el JIT en las dos, Jakarta Persistence frente a Entity Framework Core, JPQL frente a LINQ, el servidor de aplicaciones frente al servidor web integrado, y el desarrollo de interfaces con Spring Boot, MAUI, Blazor y el consumo de una API REST desde el navegador. Con los comandos exactos que ya han caído: mvn spring-boot:run, systemctl restart tomcat9, async Task, logger.LogInformation y el LifecycleListener de Catalina.
Tema desarrollado para el ejercicio único del Cuerpo de Técnicos Auxiliares de Informática de la Administración del Estado. Es el tema 5 del bloque III «Desarrollo de sistemas», que en nuestra numeración interna es el tema 19 de 33.
Cuánto pesa y cómo pregunta. Este tema tiene una peculiaridad que conviene aprovechar: el enunciado oficial pide comparar dos plataformas, y el tribunal pregunta exactamente así. «¿Qué especificación de Jakarta EE es la homóloga funcional de Entity Framework Core?». «¿Cómo se denomina el componente de .NET encargado del manejo de excepciones y de la recolección de basura?». «¿Cuál es el componente que compila el código intermedio en tiempo de ejecución?». Son preguntas de correspondencia, no de detalle, y se contestan con una tabla de equivalencias en la cabeza.
La otra mitad son comandos y fragmentos de código de los supuestos prácticos, y ahí la exigencia es la de siempre: la sintaxis exacta. mvn spring-boot:run, systemctl restart tomcat9, async Task, logger.LogInformation, la anotación que convierte una clase en controlador REST y el fichero donde se cambia el número de versión. Este apunte lleva las dos cosas: el mapa de equivalencias primero y el código literal después.
Índice
- Dos plataformas para el mismo problema
- La plataforma Java
- Componentes de Jakarta EE
- Persistencia en Java
- Seguridad en Java
- Servidores de aplicaciones
- Spring y Spring Boot
- Maven, Gradle y la construcción del proyecto
- La plataforma .NET
- Componentes de .NET
- Persistencia en .NET
- Programación asíncrona y trazas
- Desarrollo de interfaces
- El mismo caso, escrito en las dos plataformas
- El ciclo de vida de una petición, de punta a punta
- Cuadros para memorizar
- Lo que ya ha preguntado el tribunal
1. Dos plataformas para el mismo problema
1.1. Qué es una plataforma de desarrollo empresarial
Escribir una aplicación de gestión para una Administración exige resolver, una y otra vez, los mismos problemas: atender peticiones por la red, guardar y recuperar datos, controlar transacciones, autenticar usuarios, generar interfaces, registrar lo que pasa y desplegar el resultado en un servidor. Una plataforma empresarial es el conjunto de especificaciones, bibliotecas y servidores que resuelve todo eso para que el programador escriba solo la lógica de negocio.
Hay dos dominantes y llevan treinta años compitiendo: la del mundo Java, hoy llamada Jakarta EE, y la de Microsoft, hoy llamada simplemente .NET. Nacieron con filosofías opuestas —una como estándar abierto implementado por varios fabricantes, la otra como producto de una sola casa— y han acabado pareciéndose mucho: las dos son multiplataforma, las dos son de código abierto y las dos han pasado de servidores de aplicaciones pesados a procesos ligeros que se despliegan en contenedores.
La consecuencia práctica para el examen es que casi todo lo que hay en una tiene su equivalente en la otra, y de ahí la tabla que viene a continuación, que es la que resuelve las preguntas de correspondencia.
1.2. El mapa de equivalencias
| Función | Mundo Java / Jakarta EE | Plataforma .NET |
|---|---|---|
| Entorno de ejecución | JVM (máquina virtual de Java) | CLR (Common Language Runtime) |
| Código intermedio | Bytecode (ficheros .class) | CIL o MSIL |
| Compilación en ejecución | JIT | JIT (también existe compilación anticipada) |
| Lenguaje principal | Java | C# |
| Otros lenguajes | Kotlin, Scala, Groovy | F#, Visual Basic |
| Acceso a datos de bajo nivel | JDBC | ADO.NET |
| Mapeo objeto-relacional | Jakarta Persistence (con Hibernate como proveedor) | Entity Framework Core |
| Lenguaje de consulta orientado a objetos | JPQL | LINQ |
| Aplicación web y servicios | Servlets, Jakarta REST, Spring Boot | ASP.NET Core con MVC y Web API |
| Interfaz de usuario web en servidor | Páginas de servidor, JSF | Razor Pages, Blazor |
| Escritorio y móvil | JavaFX, Android | .NET MAUI, WPF, WinForms |
| Gestión de dependencias y construcción | Maven (pom.xml) o Gradle | NuGet y la herramienta de línea de órdenes |
| Servidor | Tomcat, WildFly, Payara, WebLogic | Kestrel, e IIS como intermediario |
| Fecha y hora | LocalDate, LocalTime y LocalDateTime (paquete de fechas) | DateTime, DateOnly y TimeOnly |
| Pruebas unitarias | JUnit | xUnit, NUnit, MSTest |
| Empaquetado | JAR, WAR, EAR | Ensamblados (.dll) y publicación |
🚨 Esta tabla ya ha contestado dos preguntas oficiales por sí sola. La primera: «¿qué especificación de la arquitectura Jakarta EE es la homóloga funcional de Entity Framework Core para la gestión de la persistencia?» → Jakarta Persistence. La segunda: «dentro de la plataforma .NET, ¿cómo se denomina el componente encargado del manejo de excepciones y la recolección de basura?» → el CLR. Las dos son preguntas de correspondencia pura: quien tenga las dos columnas alineadas no necesita saber nada más.
2. La plataforma Java
2.1. De Java EE a Jakarta EE
La plataforma Java se organiza en ediciones, y la distinción se pregunta:
- Java SE (edición estándar): el lenguaje, la máquina virtual y las bibliotecas básicas. Es lo que hace falta para cualquier programa Java.
- Java EE (edición empresarial): un conjunto de especificaciones añadidas sobre la anterior para aplicaciones de servidor: componentes web, transacciones, persistencia, mensajería, seguridad y servicios web. No es un producto: es un contrato que varios fabricantes implementan.
- Java ME (edición micro): la versión reducida para dispositivos limitados, hoy residual.
El cambio de nombre a Jakarta EE no es cosmético y conviene entenderlo, porque explica por qué en el código conviven dos prefijos de paquete: Oracle donó la edición empresarial a la Fundación Eclipse, que no obtuvo los derechos sobre la marca «Java», y por eso la plataforma se renombró y, a partir de su versión 9, los paquetes pasaron de empezar por javax a empezar por jakarta. Todo lo demás siguió igual. Ese detalle es la razón de que una pregunta de examen pueda citar javax.naming y javax.sql —los paquetes de siempre— y otra hablar de Jakarta Persistence: son la misma plataforma en dos momentos.
2.2. Máquina virtual, bytecode y JIT
El esquema de ejecución de Java es el que explica su portabilidad, y se pregunta pieza por pieza:
- El compilador traduce el código fuente a bytecode, un código intermedio que no es código máquina de ningún procesador real: es el juego de instrucciones de una máquina virtual.
- La máquina virtual de Java ejecuta ese bytecode. Ahí está la portabilidad: el mismo fichero corre en cualquier sistema que tenga una máquina virtual instalada.
- 🚨 Y para no perder rendimiento, el compilador JIT traduce el código intermedio a código máquina en tiempo de ejecución, guardando el resultado para las siguientes llamadas. El tribunal lo preguntó con esa definición exacta y con el enunciado situado explícitamente «en la arquitectura Java EE/Jakarta EE».
Los distractores de aquella pregunta merecen memorizarse porque son las otras piezas del entorno: el recolector de basura, que libera la memoria de los objetos que ya no tienen referencias; el propio bytecode, que es lo que se compila y no quien compila; y el kit de desarrollo, que es el conjunto de herramientas.
Dentro de la máquina virtual conviene reconocer además cómo se reparte la memoria, porque aparece en los supuestos de rendimiento: el montón guarda los objetos y es donde trabaja el recolector; la pila, una por hilo, guarda los marcos de llamada con sus variables locales; y hay zonas aparte para las clases cargadas y para el código ya compilado por el JIT. Un desbordamiento de pila viene de una recursión sin fondo; un error de memoria del montón, de objetos que nadie suelta.
2.3. JDK, JRE y las piezas del entorno
| Sigla | Qué contiene | Para quién |
|---|---|---|
| JVM | La máquina virtual que ejecuta el bytecode. | Es el núcleo de todo lo demás. |
| JRE | La máquina virtual más las bibliotecas necesarias para ejecutar. | Quien solo va a ejecutar programas. |
| JDK | El JRE más el compilador y las herramientas de desarrollo y diagnóstico. | Quien programa. |
La regla para no confundirlos: cada uno contiene al anterior. Y el dato práctico que aparece en los supuestos: las versiones de la plataforma se numeran y algunas se marcan como de soporte a largo plazo, que son las que se eligen para producción; un enunciado que hable de una versión concreta está fijando el contexto, no pidiendo memorizar el calendario.
2.4. Por qué dos plataformas y no una
Merece la pena responder a la pregunta que un opositor se hace al ver el enunciado: si las dos hacen lo mismo, ¿por qué conviven en la Administración? Por tres razones que conviene saber decir, porque son las que aparecen en un supuesto de decisión técnica.
La primera es histórica: los sistemas no se eligen, se heredan. Un organismo con veinte años de aplicaciones en una plataforma no cambia de tecnología por gusto, porque el coste no es el de reescribir sino el de volver a probar y a certificar todo lo que ya funciona.
La segunda es de personal: la plataforma que se elige es aquella para la que hay gente. Un equipo que domina una herramienta produce software mejor con ella que con otra teóricamente superior que nadie conoce, y ese cálculo pesa más que cualquier comparativa.
Y la tercera es de integración: cada plataforma encaja mejor con lo que ya hay alrededor. La de Microsoft se integra sin esfuerzo con el directorio corporativo y con la ofimática; la del mundo Java tiene detrás décadas de bibliotecas para todo y no depende de un único proveedor. Las dos son multiplataforma y de código abierto desde hace años, así que el viejo argumento de que una ataba a un sistema operativo ya no vale, y responderlo en un examen sería equivocarse.
3. Componentes de Jakarta EE
3.1. Contenedores
La idea central de la plataforma empresarial es el contenedor: un entorno que gestiona el ciclo de vida de los componentes y les proporciona servicios sin que ellos los programen. El componente declara qué necesita —una transacción, una conexión, un permiso— y el contenedor se lo da. A eso se lo llama inversión del control, y es la razón de que un programador de aplicaciones empresariales escriba muchísimo menos código de infraestructura del que parecería.
Los servicios que ofrece un contenedor, y que conviene saber enumerar: gestión del ciclo de vida de los objetos, transacciones, seguridad declarativa, concurrencia y agrupación de instancias, inyección de dependencias, acceso a recursos por nombre y gestión de conexiones.
3.2. La capa web: servlets y páginas
Un servlet es un componente Java que atiende peticiones HTTP y produce respuestas. Es la pieza más antigua y la base sobre la que se apoya todo lo demás: los marcos web modernos siguen siendo, por debajo, servlets muy bien organizados.
Sobre ellos se construyeron dos generaciones de tecnologías de presentación: primero las páginas de servidor, que mezclan marcado y código y se compilan a un servlet; y después JSF, un marco basado en componentes con su propio ciclo de vida de la petición. Hoy la tendencia dominante es otra: el servidor entrega datos en JSON mediante una API y la interfaz se construye en el navegador, que es lo que se ve en el apartado de interfaces.
Junto al servlet hay dos piezas que se preguntan por su papel: el filtro, que intercepta las peticiones antes y después para tareas transversales —autenticación, compresión, trazas—, y el escuchador, que reacciona a sucesos del ciclo de vida de la aplicación o de la sesión.
3.3. La capa de negocio
Por debajo de la web viven los componentes que hacen el trabajo. Históricamente fueron los EJB, componentes gestionados por el contenedor con transacciones y seguridad declarativas; su versión de sesión, sin estado, sigue siendo la forma canónica de escribir un servicio transaccional.
La plataforma moderna los ha simplificado con CDI, el mecanismo general de inyección de dependencias y contextos: cualquier clase puede declarar qué necesita y el contenedor se lo inyecta, con un ámbito de vida definido —de petición, de sesión, de aplicación—. Es la misma idea que Spring popularizó y que acabó absorbiendo el estándar.
3.4. Servicios web
La plataforma ofrece las dos familias, y el tema 6 de este bloque las desarrolla:
- REST: no es un protocolo sino un estilo de arquitectura. Se opera sobre recursos identificados por su dirección, con los métodos de HTTP y sus códigos de estado, y hoy se intercambia sobre todo JSON. En Jakarta EE lo cubre su especificación de servicios REST, y en la práctica lo hacen casi todos con Spring.
- SOAP: un protocolo de mensajería con su sobre, su cabecera y su cuerpo, descrito por un documento WSDL. Sigue vivo en la interoperabilidad entre Administraciones. 🚨 De ahí salió una pregunta de supuesto: para firmar las peticiones de un servicio web de naturaleza SOAP se usa WS-Security, que es la especificación que añade firma y cifrado al mensaje.
🚨 Y hay una familia de siglas que el tribunal ha usado como opciones de una misma pregunta, en 2024 y en las dos versiones del cuestionario: todas empiezan por JAX y hacen cosas distintas. Confundirlas cuesta la pregunta entera, porque el enunciado no da más pistas que el verbo.
| Sigla | Nombre | Para qué sirve, en una línea |
|---|---|---|
| JAXB | Enlace XML (XML Binding) | Mapear elementos XML a clases y al revés: convertir un objeto en XML (marshalling) y un XML en objetos (unmarshalling). Es la respuesta oficial a «qué utilizaría para mapear elementos XML a clases». |
| JAX-RS | Servicios web REST | Publicar y consumir servicios de estilo REST con anotaciones sobre los métodos. Mapea rutas y verbos HTTP, no elementos XML. |
| JAX-WS | Servicios web SOAP | Publicar y consumir servicios SOAP a partir de su WSDL. Es la pareja de JAX-RS para el otro estilo. |
| JAXR | Registros XML | Acceder a registros de servicios del tipo UDDI o ebXML para localizar proveedores. Es la más antigua y hoy la menos usada, y por eso aparece siempre como distractor. |
| JAXP | Procesamiento de XML | Leer y transformar XML: los analizadores DOM y SAX, el recorrido en flujo con StAX y las transformaciones XSLT. |
| JPA | Persistencia | Mapea clases a tablas de una base de datos relacional. No tiene nada que ver con XML, y es justo por eso el distractor más tentador de la pregunta. |
La regla que las separa cabe en una frase: JAXB enlaza con XML, JPA enlaza con tablas, JAX-RS y JAX-WS publican servicios (REST y SOAP), JAXP procesa el documento y JAXR busca en un registro. Y como el resto de la plataforma, todas cambiaron de nombre en el paso a Jakarta EE —«Jakarta XML Binding», «Jakarta RESTful Web Services»—, aunque el tribunal las sigue nombrando por sus siglas clásicas.
🚨 Y una tercera pieza de la familia SOAP que el tribunal preguntó en 2023, en el ingreso libre y en la promoción interna: WSIL. Las siglas son Web Services Inspection Language, y para no confundirla hay que verla junto a las otras dos, porque las tres responden a preguntas distintas:
| Pieza | A qué pregunta responde | Cómo funciona |
|---|---|---|
| WSDL | ¿Cómo se llama a este servicio? | Un documento XML que describe las operaciones, los tipos y la dirección del servicio. |
| UDDI | ¿Dónde busco servicios? | Un registro centralizado, una especie de páginas amarillas donde los proveedores publican. Nació con mucha ambición y quedó en desuso. |
| WSIL | ¿Qué ofrece este sitio? | Un mecanismo de inspección descentralizado: un documento colocado en el propio sitio del proveedor apunta a sus servicios y a sus descripciones. |
La diferencia de fondo entre las dos últimas es la que se pregunta: UDDI centraliza y WSIL descentraliza. En vez de consultar un directorio universal, se va al sitio del organismo y se mira qué publica; por eso WSIL sobrevivió al fracaso de los registros globales. Y ninguna de las dos describe el servicio: eso lo hace siempre WSDL.
3.5. Empaquetado y despliegue
| Formato | Qué contiene |
|---|---|
| JAR | Clases y recursos de una biblioteca o de una aplicación autónoma. |
| WAR | Una aplicación web completa: clases, páginas, recursos estáticos y su descriptor. Es lo que se despliega en un servidor de aplicaciones. |
| EAR | Varias aplicaciones y módulos empaquetados juntos. Cada vez menos usado. |
Los tres son, por dentro, ficheros comprimidos en formato ZIP con una estructura convenida y un manifiesto. Y conviene saber que el modelo ha cambiado: donde antes se generaba un archivo web y se desplegaba en un servidor ya instalado, hoy lo habitual es producir un archivo autónomo con el servidor dentro, que se ejecuta como un proceso más. Es lo que hace Spring Boot y lo que encaja con los contenedores.
4. Persistencia en Java
4.1. JDBC, el nivel de abajo
JDBC es la interfaz estándar para hablar con una base de datos relacional desde Java. Trabaja con SQL literal y devuelve conjuntos de resultados que hay que recorrer a mano. Sus piezas son cuatro —el controlador, la conexión, la sentencia y el conjunto de resultados— y sus cuatro tipos de controlador ya se estudiaron en el tema de bases de datos: puente sobre otra tecnología, biblioteca nativa del cliente, protocolo de red con intermediario y protocolo nativo escrito enteramente en Java, que es el que se usa hoy.
🚨 De aquí sale una pregunta oficial que parece de detalle y no lo es: en una aplicación Java, los paquetes que hacen falta para obtener la conexión desde un origen de datos configurado en el servidor son javax.naming y javax.sql. La lógica de la respuesta es esta: el origen de datos no se crea en el código, lo declara el servidor, así que primero hay que localizarlo por su nombre —eso es el servicio de nombres, el primer paquete— y después usarlo como origen de conexiones —el segundo—. El distractor inventaba un paquete llamado «java.database», que no existe.
⚠️ Ojo a los tres paquetes, porque se parecen y responden a preguntas distintas. El de la interfaz JDBC de toda la vida es java.sql, y es donde viven Connection, Statement, PreparedStatement y ResultSet: si el enunciado pregunta qué paquete trae las clases para hablar con la base de datos, la respuesta es ese. javax.sql es la extensión, y aporta lo de nivel empresarial: el DataSource y la agrupación de conexiones. Y javax.naming no es de datos en absoluto: es el servicio de nombres con el que se localiza un recurso que ha declarado el servidor. De ahí que la pregunta oficial —obtener la conexión desde un origen de datos configurado en el servidor— se responda con los dos últimos y no con el primero: el matiz está en de dónde sale la conexión, no en quién la usa después.
Dos conceptos que van con esto y que se preguntan por su ventaja: la agrupación de conexiones, porque abrir una conexión es caro y lo que se hace es reutilizar un juego ya abierto; y la sentencia preparada, que permite ejecutar muchas veces la misma sentencia con distintos valores y que, sobre todo, es la contramedida contra la inyección de SQL.
4.2. Jakarta Persistence, el nivel de arriba
Escribir SQL a mano para cada operación es tedioso y repetitivo, y de ahí nació el mapeo objeto-relacional. La especificación estándar de la plataforma es Jakarta Persistence —antes Java Persistence API—, y sus reglas son las que el tribunal preguntó en dos modelos de 2024:
- 🚨 «Normalmente, una entidad representa una tabla en una base de datos relacional y cada instancia de la entidad corresponde a una fila de esa tabla.» Esa es la afirmación correcta, y describe el mapeo en una frase.
- Es una especificación, no una implementación: necesita un proveedor que la haga funcionar, y el más extendido es Hibernate. Decir que «no necesita utilizar un proveedor» era una de las opciones falsas.
- Define relaciones entre entidades de tipo uno a uno, uno a muchos y muchos a muchos. Negar las de uno a muchos era otra opción falsa.
- Su lenguaje de consulta orientado a objetos se llama JPQL, no «JPSQL»: consulta entidades y sus atributos, no tablas y columnas, y el proveedor lo traduce a SQL del gestor concreto.
El resto de su vocabulario aparece en los supuestos y conviene reconocerlo: el gestor de entidades es el objeto con el que se busca, se guarda y se elimina; el contexto de persistencia es el conjunto de entidades que ese gestor está vigilando, de modo que un cambio en un objeto se escribe solo al cerrar la transacción; y la carga perezosa es la decisión de no traer las relaciones hasta que se pidan, que es cómoda y es la causa del problema de rendimiento más común del mapeo, aquel en que recorrer cien registros lanza cien consultas más.
5. Seguridad en Java
La seguridad de una aplicación empresarial se resuelve en tres niveles, y los tres se preguntan por separado.
Primero, la de la plataforma. La máquina virtual comprueba el bytecode antes de ejecutarlo, aísla el código y controla el acceso a los recursos del sistema. Es la capa que hace que un fallo de programación no se convierta automáticamente en un fallo de seguridad del servidor.
Segundo, la del contenedor, que es declarativa: se declara qué rol hace falta para acceder a qué recurso, y el contenedor lo comprueba antes de invocar el componente. Su vocabulario son los roles, los dominios de seguridad donde viven las cuentas, y los mecanismos de autenticación admitidos por la capa web —formulario, básica y por certificado de cliente—. Junto a ella existe la seguridad programática, en la que el código consulta qué usuario hay y qué roles tiene, y que se reserva para lo que la declarativa no puede expresar.
Y tercero, la de la aplicación, que es donde vive lo que de verdad falla. Aquí caben las contramedidas que el examen ha nombrado: sentencias preparadas contra la inyección, validación de entradas, cifrado en tránsito, gestión correcta de la sesión y el principio de privilegio mínimo en la cuenta con la que la aplicación ataca la base de datos.
🚨 De la autenticación entre sistemas salieron dos preguntas de supuesto que conviene tener con su respuesta exacta:
- Una petición cuya cabecera de autorización lleva la palabra Bearer seguida de una cadena en tres partes separadas por puntos es una autenticación mediante JWT, un testigo web en formato JSON. Sus tres partes son cabecera, cuerpo con las afirmaciones y firma, y el punto que las separa es lo que lo delata a simple vista.
- Para firmar las peticiones dirigidas a un servicio web SOAP se emplea WS-Security.
5.1. Los diez riesgos que hay que conocer
La lista de referencia en seguridad de aplicaciones es el OWASP Top Ten, y aunque su numeración se revisa cada pocos años, las categorías de fondo se repiten. Las que aparecen en un examen de este cuerpo, con su contramedida al lado:
| Riesgo | En qué consiste | Cómo se ataja |
|---|---|---|
| Inyección | El dato del usuario se concatena en una sentencia y el gestor lo ejecuta como código. La forma canónica es la inyección de SQL. | Sentencias preparadas, validación de entradas y privilegio mínimo en la cuenta de la aplicación. |
| Control de acceso roto | El usuario llega a un recurso que no le corresponde cambiando un identificador en la dirección. | Comprobar la autorización en el servidor y en cada petición, nunca solo ocultando el enlace. |
| Fallos criptográficos | Datos sensibles viajando o almacenados sin protección, o con algoritmos obsoletos. | Cifrado en tránsito con TLS y en reposo, y funciones de resumen específicas para contraseñas. |
| Diseño inseguro | El problema no está en el código sino en la decisión: un flujo que no contempla el abuso. | Modelado de amenazas antes de programar. |
| Configuración incorrecta | Servicios de depuración abiertos, credenciales por defecto, mensajes de error que revelan la estructura interna. | Endurecimiento del entorno y separación entre configuración de desarrollo y de producción. |
| Componentes vulnerables | Una dependencia de terceras partes con un fallo conocido. | Inventario de dependencias y análisis automático en la construcción. |
| Fallos de identificación y autenticación | Sesiones que no caducan, contraseñas débiles, ausencia de segundo factor. | Gestión correcta de la sesión y refuerzo de la autenticación. |
| Fallos de registro y supervisión | El ataque ocurre y nadie se entera porque no hay trazas o nadie las mira. | Registro con nivel adecuado y alertas. |
A esta lista se añaden dos ataques propios del navegador que conviene tener nombrados porque pertenecen al desarrollo de interfaces: el guionado entre sitios, en el que un contenido del atacante se ejecuta en el navegador de la víctima y que se ataja escapando todo lo que se pinta en la página; y la falsificación de petición entre sitios, en la que un sitio ajeno consigue que el navegador envíe una petición autenticada al nuestro, y que se ataja con un testigo por formulario y con la marca adecuada en la cookie de sesión.
5.2. La sesión, el punto donde se pierde la seguridad
HTTP no tiene memoria: cada petición llega sola. Para que el servidor sepa quién está al otro lado hacen falta mecanismos de gestión de la sesión, y ahí es donde se concentran los fallos.
- La forma clásica es una cookie con el identificador de sesión, mientras el estado vive en el servidor. Esa cookie debe marcarse para que no sea accesible desde el guion de la página, para que solo viaje por conexión cifrada y para que no se envíe desde otros sitios.
- La forma moderna en servicios es el testigo: el servidor entrega un JWT firmado y el cliente lo envía en la cabecera de autorización. Su ventaja es que no hay estado en el servidor y por eso escala bien; su inconveniente, que no se puede revocar antes de que caduque, y de ahí que se emitan con vida corta y se acompañen de un mecanismo de renovación.
- ⚠️ El contenido de un testigo va firmado, no cifrado: cualquiera puede leerlo. Meter datos personales en él es un error que se repite, porque el testigo acaba en registros, en cachés y en la barra de direcciones.
5.2.1. Los tres ataques que viven en la sesión, y sus tres defensas
Con el testigo o con la cookie, el punto débil es siempre el mismo: quien consiga la credencial es el usuario. Los tres ataques que la persiguen se preguntan por su nombre y conviene no confundirlos, porque se parecen mucho y sus defensas son distintas.
| Ataque | Qué hace el atacante | Defensa |
|---|---|---|
| XSS, secuencias de órdenes en sitios cruzados | Consigue que la página devuelva un dato suyo sin escapar, de modo que el navegador de la víctima lo ejecuta como código y le roba la cookie. | Escapar la salida según el contexto, marcar la cookie como HttpOnly y aplicar una política de seguridad de contenidos. |
| CSRF, falsificación de peticiones en sitios cruzados | No roba nada: hace que el propio navegador de la víctima, que ya tiene la sesión abierta, envíe una petición preparada desde otra página. | Un testigo antifalsificación por formulario y la marca SameSite en la cookie, que impide enviarla desde otro sitio. |
| Fijación de sesión | Planta él un identificador de sesión ANTES de que la víctima entre; si al autenticarse el identificador no cambia, hereda una sesión ya elevada. | Regenerar el identificador en el momento de autenticar. Es la única defensa real, y la que suele olvidarse. |
⚠️ La diferencia entre los dos primeros es la que más se falla: XSS ejecuta código en la víctima; CSRF no ejecuta nada, se aprovecha de que la sesión ya está abierta. Uno roba la credencial y el otro la usa sin verla.
De ahí que las tres marcas de la cookie de sesión se pregunten juntas, y que valga la pena aprenderlas con lo que hace cada una:
- HttpOnly: la cookie deja de ser visible para JavaScript, así que un XSS ya no puede leerla.
- Secure: la cookie solo viaja por conexiones cifradas, así que no se cae en una red abierta.
- SameSite: la cookie no se envía —o solo se envía en navegaciones de primer nivel— cuando la petición nace en otro sitio, que es la mitigación de CSRF.
5.2.2. CORS: por qué el navegador bloquea una llamada que la API responde bien
Este no es un ataque, sino la defensa que trae de serie el navegador, y aparece en cuanto la interfaz web y la API viven en direcciones distintas. La regla de partida es la política del mismo origen: una página solo puede leer respuestas de su propio origen, entendiendo por origen la terna de esquema, dominio y puerto. Cambiar cualquiera de los tres —de http a https, del 8080 al 3000— ya es otro origen.
CORS —Cross-Origin Resource Sharing— es el mecanismo por el que el servidor autoriza expresamente esa lectura, devolviendo cabeceras que dicen qué orígenes, qué métodos y qué cabeceras admite. Tres consecuencias prácticas que se preguntan:
- Lo aplica el navegador, no el servidor. Por eso la misma petición hecha con una herramienta de línea de órdenes funciona y desde la página falla: no es que la API esté caída, es que el navegador se niega a entregar la respuesta al guion.
- Para ciertas peticiones el navegador manda antes una comprobación previa con el método OPTIONS, y si esa no se responde bien, la de verdad ni se envía.
- No es un mecanismo de seguridad del servidor: no protege la API. Un cliente que no sea un navegador la llama igual, así que la autenticación y la autorización siguen siendo obligatorias.
5.3. La seguridad como obligación jurídica
En una Administración esto no es solo buena práctica. El Esquema Nacional de Seguridad impone medidas por dimensiones —confidencialidad, integridad, trazabilidad, autenticidad y disponibilidad— y varias caen del lado del desarrollo: el control de acceso, el registro de la actividad de los usuarios, la protección de las comunicaciones y la gestión del ciclo de vida de las aplicaciones. Y el marco de protección de datos añade dos exigencias que se diseñan, no se parchean: protección desde el diseño y por defecto y minimización, es decir, tratar solo los datos necesarios y con la configuración más protectora de partida.
La consecuencia práctica para el desarrollo es concreta: los entornos de prueba no se cargan con una copia de producción sin tratar, y las trazas no llevan datos personales. Las dos son de las brechas más frecuentes y las dos se evitan con una decisión de diseño, no con una herramienta.
6. Servidores de aplicaciones
Un servidor de aplicaciones implementa el contenedor y ofrece los servicios de la plataforma. Conviene distinguir dos categorías, porque el tribunal juega con ellas:
| Tipo | Qué implementa | Ejemplos |
|---|---|---|
| Contenedor web | Solo la parte web: servlets y páginas. | Apache Tomcat, Jetty |
| Servidor de aplicaciones completo | Toda la plataforma empresarial. | WildFly, Payara, WebLogic, WebSphere, Open Liberty |
El más preguntado es Tomcat, y de él han caído dos cosas concretas:
- 🚨 Su motor interno se llama Catalina, y para ejecutar código de limpieza cuando ese motor se detiene por completo pero antes de que la máquina virtual termine, la solución correcta es implementar un LifecycleListener y registrarlo en el elemento del servidor del fichero de configuración. La lógica: Tomcat modela sus componentes con un ciclo de vida que emite sucesos, y engancharse al suceso de parada del componente más externo es la única forma de que el código corra después de todo lo demás.
- ⚠️ El distractor de esa misma pregunta era @PreDestroy, y conviene saber exactamente por qué no vale. Las anotaciones de ciclo de vida del contenedor —@PostConstruct, que se ejecuta después de construir e inyectar el componente, y @PreDestroy, que se ejecuta antes de destruirlo— pertenecen al ciclo de vida de ese componente, no al del servidor: el contenedor las invoca cuando retira el objeto, que puede ser mucho antes del apagado y que, en un cierre brusco, puede no ocurrir. Sirven para soltar lo que el propio componente reservó —una conexión, un fichero, un temporizador—, no para código que tiene que correr cuando ya no queda nada más en pie. Los otros dos distractores fallan por los extremos contrarios: un gancho de apagado de la máquina virtual (shutdown hook) corre demasiado tarde, cuando Catalina ya se ha desmontado, y una válvula (Valve) es una pieza que intercepta peticiones mientras el servidor funciona, no sucesos de su ciclo de vida.
- 🚨 Y en un servidor Linux, reiniciar el servicio se hace con el gestor de servicios del sistema: systemctl restart tomcat9, con el nombre de la unidad tal cual, sin rutas ni guiones adicionales.
- 🚨 Y el gemelo del otro lado: en Windows, reiniciar IIS se hace con IISRESET, una orden de una sola palabra. El tribunal la preguntó rodeada de las tres variantes que parecen razonables y no existen —«IIS RESET» con espacio, «RESET IIS» invertido y «RESETIIS» pegado al revés—, así que aquí no se razona nada: se reconoce. La orden detiene y vuelve a arrancar todos los servicios de IIS de la máquina; para tocar un solo sitio o un solo grupo de aplicaciones, la herramienta es appcmd.
De su configuración conviene reconocer los ficheros: el fichero del servidor, con los conectores y los puertos; el descriptor de la aplicación web, con los servlets y sus asignaciones; y el directorio donde se dejan los archivos web para que el servidor los despliegue.
🚨 Los tres nombres propios de Tomcat se preguntan por separado, y con ellos se entiende cualquier línea de su registro de arranque:
- Catalina es el contenedor de servlets, el motor: quien crea los servlets, los asocia a sus rutas y gestiona su ciclo de vida. Es el nombre que aparece en el fichero de trazas principal.
- Coyote es el conector: quien habla HTTP con el exterior, escucha en el puerto y convierte la petición de red en un objeto que Catalina entiende.
- Jasper es el motor de páginas de servidor: quien traduce una página con marcas a una clase de servlet y la compila la primera vez que se pide.
Y una pieza más que el tribunal metió en un supuesto de 2026: cómo ejecutar código de limpieza cuando el motor se detiene. La respuesta no es un servlet ni un filtro, sino un oyente del contexto de servlets, una clase que se registra y a la que el contenedor avisa dos veces:
@WebListener
public class ArranqueYParada implements ServletContextListener {
public void contextInitialized(ServletContextEvent e) { /* al desplegar */ }
public void contextDestroyed(ServletContextEvent e) { /* al parar */ }
}
La distinción que hay que tener clara es de alcance: el filtro y el servlet trabajan por petición, y el oyente trabaja por ciclo de vida de la aplicación o de la sesión. Cerrar un conjunto de conexiones, detener un planificador de tareas o volcar una caché va en el segundo método del oyente; ponerlo en un filtro significaría ejecutarlo miles de veces.
Para gobernar el servidor cuando está instalado como servicio del sistema, la orden es la del gestor de servicios —systemctl restart tomcat en las distribuciones actuales de Linux—, y no el guion propio del contenedor, cuyos argumentos son arrancar y parar pero no reiniciar.
7. Spring y Spring Boot
Spring no forma parte del estándar: es un marco de trabajo independiente que acabó siendo más popular que la plataforma que venía a simplificar. Su núcleo es un contenedor de inversión de control que crea los objetos y les inyecta sus dependencias, y sobre él se han construido módulos para casi todo: acceso a datos, web, seguridad, mensajería y pruebas.
Spring Boot es la capa que lo hizo dominante. Su aportación es la configuración por convención: incorpora un servidor web dentro del propio archivo ejecutable, autoconfigura lo que detecta en el proyecto y arranca la aplicación con un solo comando, sin descriptor ni despliegue en un servidor externo.
🚨 Las tres preguntas de supuesto que ha puesto el tribunal, con su respuesta y su razón:
- Crear un controlador REST que devuelva todos los alumnos por GET. La forma correcta anota la clase como controlador REST y el método con la anotación de mapeo de GET indicando la ruta:
@RestController public class AlumnoController { @GetMapping("/alumnos") public List<Alumno> obtenerAlumnos() { return repository.findAll(); } }Las dos anotaciones son las que hacen el trabajo: la de la clase indica que lo que devuelvan sus métodos se serializa directamente al cuerpo de la respuesta —sin buscar una vista—, y la del método fija verbo y ruta. - Ejecutar la aplicación. El comando de Maven es mvn spring-boot:run: el nombre del complemento, dos puntos y el objetivo. Es la forma canónica de invocar cualquier objetivo de un complemento de Maven.
- Cambiar el número de versión de la API. El fichero es pom.xml, que es donde Maven guarda las coordenadas del proyecto, su versión y sus dependencias.
7.1. Los módulos de Spring que conviene reconocer
Spring no es una pieza sino una familia, y los enunciados citan sus módulos por su nombre. Estos son los que aparecen:
| Módulo | Para qué |
|---|---|
| Spring Core | El contenedor de inversión de control y la inyección de dependencias. Es el cimiento de todo lo demás. |
| Spring MVC | La capa web: controladores, enrutado y vistas o datos. |
| Spring Data | Los repositorios que se declaran como interfaz y el marco implementa, sobre la especificación de persistencia o sobre bases NoSQL. |
| Spring Security | Autenticación y autorización declarativas, con su cadena de filtros. |
| Spring Boot | La capa de arranque: servidor incorporado, autoconfiguración y un ejecutable autónomo. |
| Spring Cloud | Las piezas para microservicios: descubrimiento de servicios, configuración centralizada y tolerancia a fallos. |
Y una advertencia de vocabulario que evita un error frecuente: Spring no forma parte de Jakarta EE. Es un proyecto independiente que usa algunas de sus especificaciones —la de persistencia, la de validación, la de servlets— y prescinde de otras. Por eso una aplicación de Spring Boot no se despliega en un servidor de aplicaciones completo: lleva su propio contenedor web dentro y se ejecuta como un proceso corriente. Confundir las dos cosas es lo que lleva a responder que Spring es «la implementación de referencia» de algo, y no lo es de nada.
8. Maven, Gradle y la construcción del proyecto
Compilar a mano una aplicación con cuarenta dependencias es inviable, y de ahí las herramientas de construcción. Maven es la más extendida en el mundo Java y funciona con tres ideas:
- Un modelo de objetos del proyecto, el fichero pom.xml, que declara qué es el proyecto —grupo, nombre y versión— y de qué depende.
- Un repositorio del que se descargan las dependencias declaradas, con sus propias dependencias arrastradas de forma transitiva.
- Un ciclo de vida por fases con nombres fijos —validar, compilar, probar, empaquetar, verificar, instalar y desplegar—, de modo que invocar una fase ejecuta todas las anteriores.
Su alternativa es Gradle, que sustituye el fichero declarativo por un guion programable y añade compilación incremental. Y en el mundo .NET el papel lo reparten NuGet, que gestiona los paquetes, y la herramienta de línea de órdenes de la plataforma, que restaura, compila, prueba y publica.
🚨 Y de esa herramienta han caído los mandatos exactos, que conviene reconocer porque el examen los pone rodeados de permutaciones falsas. Para añadir el paquete de Entity Framework Core a un proyecto, el tribunal dio por correcta la forma sustantivo primero:
dotnet package add Microsoft.EntityFrameworkCore
⚠️ Esa respuesta desconcierta a quien lleve años escribiendo dotnet add package, que es la forma clásica y sigue funcionando. La plataforma reorganizó su línea de órdenes agrupando los mandatos por el objeto sobre el que actúan —paquete, referencia, solución— en lugar de por el verbo, y esa es la forma moderna. La lección para el examen es doble: las dos existen, y cuando aparezcan las cuatro permutaciones hay que fijarse en cuál nombra el objeto y luego la acción, que es la que el tribunal marcó. Los otros dos distractores se descartan solos porque les falta una de las dos palabras.
Del mismo juego de herramientas conviene reconocer dotnet restore para descargar las dependencias declaradas, dotnet build para compilar, dotnet run para ejecutar, dotnet test para las pruebas y dotnet publish para dejar el resultado listo para desplegar. Y el fichero donde vive todo eso —el equivalente del pom.xml— es el .csproj del proyecto.
El vocabulario que conviene tener claro porque el examen lo usa: una dependencia es una biblioteca de la que depende el proyecto; una dependencia transitiva es la que arrastra una dependencia; y un conflicto de versiones ocurre cuando dos dependencias piden versiones distintas de una tercera, que es el problema clásico de este tipo de herramientas y la razón de que existan mecanismos para fijar una versión concreta.
8.1. El número de versión: versionado semántico
🚨 El tribunal preguntó en 2026 qué número hay que subir tras modificar una interfaz, y la respuesta sale de un convenio con nombre propio: el versionado semántico. El número tiene tres cifras separadas por puntos, y cada una significa algo:
| Cifra | Nombre | Cuándo sube |
|---|---|---|
| La primera | Mayor | Cuando el cambio rompe la compatibilidad: se quita un método, cambia el tipo de un parámetro, desaparece un campo de la respuesta. |
| La segunda | Menor | Cuando se añade algo y lo anterior sigue funcionando: un método nuevo, un campo opcional más. |
| La tercera | Parche | Cuando solo se corrige un error, sin tocar nada de lo que se ve desde fuera. |
Al número puede seguirle un guion con una etiqueta de versión previa —alfa, beta, rc—, que indica que esa versión aún no es estable y que se ordena ANTES que la definitiva del mismo número.
La utilidad no es burocrática: es lo que permite fijar dependencias con seguridad. Aceptar automáticamente los parches y las versiones menores de una biblioteca es razonable porque, por convenio, no rompen; aceptar una versión mayor es lo que hay que revisar a mano. En el mundo Java el sufijo -SNAPSHOT marca además la versión en desarrollo, que Maven vuelve a descargar cada vez porque puede haber cambiado sin que cambie su número.
9. La plataforma .NET
9.1. De .NET Framework a .NET
La historia importa porque explica los nombres que aparecen en los enunciados:
- .NET Framework fue la plataforma original, solo para Windows, y sigue en mantenimiento en muchas aplicaciones heredadas de la Administración.
- .NET Core fue su reescritura multiplataforma y de código abierto, capaz de ejecutarse también en Linux y macOS.
- Con la unificación, la palabra «Core» desapareció del nombre de la plataforma y hoy se dice simplemente .NET, aunque algunos componentes la conservan —es el caso de ASP.NET Core y de Entity Framework Core—, y de ahí que en las opciones de examen convivan las dos formas.
9.2. CLR, CIL, CTS y CLS
Las cuatro siglas que sostienen la plataforma, y la primera es la que ha caído:
| Sigla | Qué es |
|---|---|
| CLR Common Language Runtime | El entorno de ejecución: carga los ensamblados, compila con el JIT, gestiona la memoria con su recolector de basura, controla el manejo de excepciones y aplica la seguridad. 🚨 Es la respuesta a la pregunta oficial por el componente encargado del manejo de excepciones y la recolección de basura. |
| CIL o MSIL Common Intermediate Language | El código intermedio al que compilan todos los lenguajes de la plataforma, equivalente al bytecode de Java. |
| CTS Common Type System | El sistema de tipos común: define cómo se declaran y se usan los tipos, y es lo que permite que un objeto creado en un lenguaje se use desde otro. |
| CLS Common Language Specification | El subconjunto de reglas que un lenguaje debe cumplir para ser interoperable con los demás de la plataforma. |
Y una pieza más que aparece en el vocabulario: el ensamblado es la unidad de despliegue y de versionado —normalmente un fichero con extensión de biblioteca—, y contiene el código intermedio más los metadatos que lo describen. Que el propio ensamblado se describa a sí mismo es lo que hace posible la reflexión y las herramientas de análisis.
9.3. Los lenguajes
La plataforma es multilenguaje por diseño: todos compilan al mismo código intermedio y comparten el mismo sistema de tipos. Los tres que conviene reconocer son C#, que es el principal y el que aparece en todos los supuestos; F#, funcional, del que ya se estudió que su palabra clave de enlace asocia un nombre a un valor o a una función y que sus asociaciones son inmutables por omisión; y Visual Basic, heredado.
10. Componentes de .NET
| Componente | Para qué sirve |
|---|---|
| ASP.NET Core | El marco para aplicaciones y servicios web. Dentro de él conviven el patrón MVC, las páginas Razor y las API web, y todas comparten el mismo canal de procesamiento de la petición. |
| Blazor | Construir interfaces web con C# en vez de JavaScript, ejecutándose en el servidor o directamente en el navegador sobre WebAssembly. |
| .NET MAUI | 🚨 Marco multiplataforma para crear aplicaciones móviles y de escritorio nativas con C# y XAML. Es la definición literal que el tribunal dio por buena en dos modelos de 2024, y también la respuesta a «qué marco se puede usar para aplicaciones de escritorio nativas». Los distractores decían que era solo para Android y que era una herramienta de pruebas. |
| WPF y WinForms | Los marcos de escritorio clásicos, solo para Windows. |
| ADO.NET | 🚨 El componente de la plataforma para la comunicación con bases de datos. Es el nivel bajo, equivalente a JDBC. |
| Entity Framework Core | El mapeador objeto-relacional, equivalente a Jakarta Persistence con su proveedor. |
Y una pieza transversal que conviene nombrar porque marca la diferencia con la plataforma antigua: el contenedor de inyección de dependencias viene incorporado. No hace falta un marco externo: los servicios se registran al arrancar la aplicación y el sistema los proporciona a quien los declare en su constructor. Es la misma inversión del control del contenedor de Jakarta EE y del contenedor de Spring.
10.1. El canal de la petición y los intermediarios
La pieza que organiza ASP.NET Core es el canal de procesamiento: la petición atraviesa una serie de componentes encadenados —cada uno se llama middleware— y la respuesta vuelve por el mismo camino en sentido inverso. Cada componente decide si hace su trabajo y pasa la petición al siguiente, o si la corta ahí mismo y responde.
El orden en que se registran importa y es la fuente de errores más común: si la comprobación de autenticación se coloca después del enrutado que ya ha ejecutado la acción, no sirve de nada. Los intermediarios habituales, en el orden en que suelen ir, son el manejador de excepciones, la redirección a conexión segura, los ficheros estáticos, el enrutado, la autenticación, la autorización y finalmente el punto que ejecuta la acción.
El equivalente en el mundo Java son los filtros del contenedor de servlets y las cadenas de filtros de seguridad de Spring, con exactamente la misma idea y el mismo problema de orden. Reconocer que las dos plataformas resuelven así lo transversal ahorra estudiar dos veces lo mismo.
10.2. MVC, páginas y API en el mismo marco
Sobre ese canal conviven tres formas de escribir una aplicación, y el examen las nombra por separado:
- MVC: controladores con acciones que devuelven vistas. El servidor genera el HTML.
- Razor Pages: una página y su modelo juntos, pensado para formularios sencillos sin la ceremonia del controlador.
- API web: controladores cuyas acciones devuelven datos, normalmente JSON, para que los consuma otro sistema o el propio navegador. Es el equivalente exacto del controlador REST de Spring Boot.
Y una forma más reciente, la API mínima, en la que las rutas se declaran directamente al arrancar la aplicación sin necesidad de crear clases de controlador. Es la respuesta de la plataforma a la ligereza que buscaban los microservicios.
10.3. Blazor, o escribir la interfaz web en C#
Blazor permite construir la interfaz con componentes escritos en C# en lugar de JavaScript, y tiene dos modelos de ejecución que conviene distinguir porque tienen consecuencias muy distintas:
| Modelo | Dónde se ejecuta | Consecuencia |
|---|---|---|
| En servidor | El código corre en el servidor y el navegador solo recibe los cambios de la interfaz por una conexión permanente. | Descarga inicial mínima, pero necesita conexión continua y consume recursos del servidor por cada usuario. |
| En el navegador | El código se descarga y se ejecuta en el propio navegador sobre WebAssembly. | Funciona sin conexión permanente y descarga trabajo del servidor, a cambio de una descarga inicial mayor. |
La elección es la misma disyuntiva de siempre entre servidor y cliente, y la respuesta profesional depende de la red y del número de usuarios simultáneos, no de la moda.
10.4. Configuración por entorno
Una aplicación se ejecuta al menos en tres entornos —desarrollo, preproducción y producción— y necesita valores distintos en cada uno: la cadena de conexión, el nivel de traza, las direcciones de los servicios externos. Las dos plataformas resuelven esto igual y conviene saber cómo, porque aparece en los supuestos de despliegue:
- Hay un fichero de configuración base y ficheros que lo sobrescriben por entorno, seleccionados por una variable del sistema. En el mundo Spring se llaman perfiles; en .NET, entornos.
- Por encima de los ficheros mandan las variables de entorno, y por encima de estas, los argumentos de la línea de órdenes. Ese orden de precedencia es lo que permite desplegar la misma imagen de contenedor en tres entornos cambiando solo variables.
- ⚠️ Y la regla que no admite excepción: las contraseñas y las claves no se guardan en el repositorio. Van en variables de entorno, en un almacén de secretos o en el gestor de configuración de la plataforma, nunca en un fichero versionado.
10.5. Salud, métricas y despliegue
Una aplicación moderna publica información sobre sí misma para que la infraestructura pueda gestionarla sin intervención humana:
- Un punto de salud que responde si la aplicación está viva y si sus dependencias —la base de datos, los servicios externos— responden. Es lo que consulta un balanceador para decidir si le manda tráfico, y lo que consulta un orquestador de contenedores para decidir si la reinicia.
- Métricas —peticiones por segundo, tiempos de respuesta, uso de memoria— expuestas para que las recoja un sistema de supervisión.
- Y el empaquetado en contenedor, que es hoy la forma normal de desplegar en las dos plataformas: la aplicación con su servidor dentro, una imagen inmutable y la configuración por variables. Es lo que ha desdibujado la vieja frontera entre «servidor de aplicaciones» y «aplicación».
11. Persistencia en .NET
11.1. ADO.NET y Entity Framework Core
El esquema es el mismo que en Java, con dos niveles. Abajo, ADO.NET, que trabaja con SQL literal a través de una conexión, una orden y un lector de resultados. Arriba, Entity Framework Core, que mapea clases a tablas y ofrece un contexto que hace de unidad de trabajo: se consultan y se modifican objetos y, al guardar, el marco genera las sentencias necesarias dentro de una transacción.
Sus dos formas de trabajo se preguntan por su nombre: código primero, en la que las clases mandan y el esquema de la base se genera y se evoluciona con migraciones; y base de datos primero, en la que se parte de un esquema existente y se generan las clases. En una Administración con bases de datos heredadas, la segunda es lo habitual.
11.2. LINQ, el equivalente de JPQL
LINQ es la consulta integrada en el lenguaje: en lugar de escribir la consulta como una cadena de texto, se escribe con las construcciones del propio C#, con lo que el compilador la comprueba y el editor la autocompleta. Y cuando la fuente es una base de datos, el marco traduce esa consulta a SQL en lugar de traerse los datos y filtrarlos en memoria.
🚨 La pregunta de supuesto pedía obtener todos los usuarios cuyo primer apellido contenga una cadena guardada en una variable, y la respuesta correcta era:
await context.Usuarios.Where(u => u.Apellido1.Contains(texto)).ToListAsync();
Merece desmontarse porque tiene cuatro piezas y cada una responde a algo del enunciado: context.Usuarios es el conjunto de entidades; Where con una expresión lambda es el filtro, que se traducirá a la cláusula de condición del SQL; Contains es lo que se convierte en una comparación con comodines a los dos lados; y await con la versión asíncrona del método es lo que evita bloquear el hilo mientras la base de datos responde, que es la forma correcta de hacer entrada y salida en esta plataforma.
11.3. El objeto POCO
POCO es el acrónimo de Plain Old CLR Object y es el equivalente exacto del POJO del mundo Java: una clase corriente que no depende del marco. Ese es el motivo de que exista el nombre —hubo una época en que persistir un objeto obligaba a heredar de una clase base del marco, y eso ataba el modelo de datos a la herramienta—; hoy Entity Framework Core trabaja con POCO, y por eso las entidades del ejemplo son clases sin nada especial.
🚨 El tribunal lo preguntó por descarte, pidiendo la afirmación INCORRECTA, y usa una definición estricta que conviene retener tal cual, aunque en el uso profesional el término se emplee con más holgura:
| Lo que el tribunal da por bueno | Lo que marcó como falso |
|---|---|
| Es una estructura de datos que solo contiene propiedades o campos públicos. | Que pueda contener miembros como métodos, eventos y delegados. Esa es la opción INCORRECTA y, por tanto, la respuesta. |
| Es el acrónimo de Plain Old CLR Object. | |
| No hereda de otra clase ni implementa una interfaz. |
Dicho de otro modo: para este tribunal un POCO es datos y nada más, muy cerca de lo que en otros contextos se llama objeto de transferencia de datos. Si en el examen aparece un POCO «con lógica dentro», es falso.
12. Programación asíncrona y trazas
12.1. Asíncrona
Una aplicación de servidor pasa la mayor parte del tiempo esperando: a la base de datos, a otro servicio, al disco. Si cada espera bloquea un hilo, el servidor se queda sin hilos con una carga moderada aunque el procesador esté ocioso. La programación asíncrona resuelve eso: el hilo se libera durante la espera y vuelve a recoger el trabajo cuando la respuesta llega.
🚨 La pregunta de 2026, en los dos modelos, pedía la forma correcta de definir un método asíncrono en C#, y era async Task DevolverDato(). Las dos piezas son obligatorias y cada una hace algo distinto:
- La palabra async marca el método como asíncrono y habilita dentro de él la espera no bloqueante.
- El tipo devuelto es una tarea: representa una operación en curso, no un valor. Si el método devuelve algo, se declara la tarea con el tipo del resultado entre corchetes angulares.
Y con ella va una convención que aparece en el código de los supuestos: los métodos asíncronos suelen terminar en Async, como se ve en la consulta del apartado anterior. En el mundo Java el equivalente se resuelve con futuros completables y con los marcos reactivos, con la misma idea de fondo.
12.2. Trazas y diagnóstico
Cuando una aplicación se comporta mal en producción, lo único que queda son las trazas. Escribir por la salida estándar no vale: hace falta un sistema de registro con niveles, con destinos configurables y con contexto.
🚨 Cayó en los dos modelos de 2026: la forma correcta de incluir una traza informativa en una aplicación .NET es logger.LogInformation("…"). Se obtiene un registrador por inyección de dependencias y se invoca el método del nivel que corresponda.
Los niveles son de menor a mayor gravedad, y elegirlos bien es lo que hace útil un registro: traza y depuración para el desarrollo, información para los hitos del flujo normal, advertencia para lo que no debería pasar pero se ha podido continuar, error para la operación que ha fallado y crítico para lo que deja el sistema inservible. En producción se suele dejar el corte en información o en advertencia, y se sube temporalmente cuando hace falta investigar.
⚠️ Y una regla que en la Administración no es opcional: en las trazas no se escriben datos personales, contraseñas ni testigos de sesión. Un registro es un fichero que se copia, se envía y se conserva, y el contenido que caiga ahí hereda todas las obligaciones de protección de datos sin ninguna de sus protecciones.
13. Desarrollo de interfaces
El enunciado del tema termina con «desarrollo de interfaces», y la palabra tiene dos significados que conviene separar porque el examen pregunta por los dos: la interfaz de usuario, que es lo que la persona ve, y la interfaz de programación, que es por donde hablan dos sistemas.
13.1. La interfaz de usuario
Hay tres familias, y cada plataforma ofrece las tres:
| Familia | Dónde se ejecuta la interfaz | En Java | En .NET |
|---|---|---|---|
| Web en servidor | El servidor genera el HTML y el navegador lo muestra. | Páginas de servidor, JSF, plantillas | Razor Pages, vistas de MVC |
| Web en cliente | El navegador construye la interfaz y pide datos al servidor. | Marcos de JavaScript sobre una API REST | Lo mismo, o Blazor con C# |
| Nativa | Una aplicación instalada en el equipo o en el móvil. | JavaFX, Android | .NET MAUI, WPF |
La tendencia dominante es la segunda, y de ahí que el trabajo del servidor se haya desplazado de generar páginas a publicar datos. Eso es lo que convierte la interfaz de programación en el centro del asunto.
13.2. La interfaz de programación: REST y HTTP
Una API REST expone recursos identificados por su dirección y se opera sobre ellos con los métodos de HTTP. Dos clasificaciones se preguntan:
| Método | ¿Seguro? | ¿Idempotente? | Para qué |
|---|---|---|---|
| GET | Sí | Sí | Leer. No debe modificar nada. |
| PUT | No | Sí | Reemplazar el recurso entero. Repetirlo deja el mismo estado. |
| DELETE | No | Sí | Borrar. Repetirlo no borra dos veces. |
| POST | No | No | Crear o ejecutar. Repetirlo crea dos. |
| PATCH | No | No necesariamente | Modificar una parte del recurso. |
🚨 El tribunal preguntó exactamente por ese cruce: «¿cuál de los siguientes métodos es idempotente pero NO seguro?» → PUT. Las dos palabras hay que tenerlas definidas por separado: seguro quiere decir que no modifica el estado del servidor, y solo lo es la lectura; idempotente quiere decir que repetir la petición deja el mismo resultado que hacerla una vez, y lo son todos menos la creación.
Y las clases de códigos de estado, que también han caído:
| Clase | Significado |
|---|---|
| 1xx | Informativos. |
| 2xx | Éxito. El 200 es correcto y el 201, recurso creado. |
| 3xx | Redirección. |
| 4xx | 🚨 Error del CLIENTE. El 400 es petición mal formada, el 401 no autenticado, el 403 sin permiso y el 404 no encontrado. |
| 5xx | Error del servidor. El 500 es el genérico y el 503, servicio no disponible. |
La distinción entre las dos últimas familias es la que se pregunta y la que más se falla en la práctica profesional: devolver un 500 cuando el usuario ha enviado un dato inválido convierte un error del cliente en una alarma del servidor, y al revés, devolver un 400 cuando ha fallado la base de datos esconde una avería real.
13.3. Consumir la API desde el navegador
🚨 El otro extremo también cayó en un supuesto: hacer una llamada REST desde JavaScript para obtener un listado. La respuesta correcta usa la función de red del propio navegador y encadena dos promesas:
fetch("http://localhost:8080/alumnos")
.then(response => response.json())
.then(data => console.log(data));
La lógica de las dos etapas es lo que hay que entender: la primera devuelve la respuesta cuando llegan las cabeceras, y convertir su cuerpo a un objeto —segunda etapa— es otra operación asíncrona, porque el cuerpo puede seguir llegando. De ahí que hagan falta dos encadenamientos y no uno.
13.3.1. Documentar la interfaz: OpenAPI
Una API sin documentación no se puede consumir, y escribirla a mano garantiza que quede desfasada a la primera semana. La solución asentada es OpenAPI, una especificación que describe la interfaz en un documento legible por máquinas —en JSON o en YAML— con sus rutas, sus verbos, sus parámetros, sus esquemas de datos y sus posibles respuestas.
Lo que importa para el examen es de dónde sale ese documento y para qué sirve:
- Se genera desde el código, leyendo las anotaciones de los controladores, así que cambia cuando cambia la API y no puede quedarse atrás.
- De él sale una página de documentación navegable —la interfaz de Swagger es la más conocida— desde la que además se pueden lanzar peticiones de prueba sin salir del navegador.
- Y de él salen también clientes generados en el lenguaje que se quiera, porque el documento es suficiente para escribir el código que llama.
⚠️ Conviene no confundir tres nombres que aparecen juntos: OpenAPI es la especificación, Swagger es el conjunto de herramientas que la implementa y WSDL es su equivalente en el mundo SOAP. Cuando el enunciado hable de describir un servicio REST, la respuesta es la primera; si habla de SOAP, la tercera.
13.4. Probar la interfaz
🚨 Y una última pieza que el tribunal metió en el mismo supuesto: verificar con JUnit que un método lanza la excepción esperada. La forma correcta es:
@Test
void testException() {
AlumnoService service = new AlumnoService();
assertThrows(IllegalArgumentException.class, () -> service.obtenerMatriculas(-1));
}
La afirmación recibe dos cosas: la clase de la excepción que se espera y un fragmento de código que debería lanzarla, escrito como expresión lambda para que la biblioteca lo ejecute dentro de su propio bloque de captura. Escribir la llamada directamente, sin envolverla, haría que la excepción se propagara y la prueba fallara: ese es el error que ponían los distractores.
13.4.1. La pirámide de pruebas y su vocabulario
La imagen que se usa para ordenarlas es una pirámide: muchas pruebas abajo, baratas y rápidas, y pocas arriba, caras y lentas. Los tres pisos y sus nombres se preguntan tal cual:
| Piso | Qué comprueba | Con qué se escribe |
|---|---|---|
| Unitarias (la base) | Una clase aislada, con sus dependencias sustituidas por dobles. Rápida y precisa: cuando falla, señala el sitio exacto. | JUnit en Java, NUnit o xUnit en .NET. |
| De integración | Que las piezas encajan de verdad: el repositorio contra una base real, el controlador contra el servicio. | Las mismas bibliotecas, más un contenedor de pruebas o una base en memoria. |
| De extremo a extremo (la cima) | El sistema completo desplegado, conducido como lo haría un usuario por la interfaz. | Herramientas que gobiernan un navegador real. |
🚨 El tribunal pregunta por las anotaciones concretas, y las de NUnit aparecieron en el supuesto de 2026. Conviene llevar las cuatro con lo que marca cada una, porque los distractores son siempre las otras tres:
- [TestFixture] marca la clase que agrupa las pruebas.
- [Test] marca cada método de prueba.
- [SetUp] marca el método que se ejecuta antes de cada prueba.
- [TearDown] marca el de limpieza posterior.
En JUnit las equivalentes se escriben con arroba y con otros nombres —la de prueba, y las de antes y después de cada método—, pero la idea es la misma.
Tres términos más que caen y que conviene no confundir:
- Un doble de prueba es un objeto que sustituye a una dependencia real. Cuando además se le programa qué devolver y se comprueba cómo se le ha llamado, se habla de objeto simulado; las bibliotecas típicas son Mockito en Java y Moq en .NET. ⚠️ Mockito NO pertenece a la Fundación Apache, aunque el tribunal haya jugado con un nombre inventado que se le parece.
- La cobertura mide qué proporción del código llegan a ejecutar las pruebas, por líneas o por ramas. Es una medida de cantidad, no de calidad: se puede tener una cobertura altísima sin verificar nada, si las pruebas recorren el código pero no comprueban el resultado.
- Una prueba de humo es la comprobación rápida, tras desplegar, de que lo esencial responde. No sustituye a nada: solo evita dar por buena una versión que ni siquiera arranca.
13.5. Accesibilidad y bibliotecas de documentos
La interfaz de una aplicación pública tiene una obligación jurídica de accesibilidad, y sus cuatro principios se preguntan por su nombre a partir de la descripción. Son los de las pautas WCAG del W3C:
| Principio | Qué exige | Ejemplo que cae |
|---|---|---|
| Perceptible | Que la información se pueda percibir por más de un sentido. | Texto alternativo en las imágenes, contraste suficiente. |
| Operable | Que la interfaz y la navegación se puedan manejar, incluido sin ratón. | Recorrer y activar todo con el teclado; sin trampas de foco. |
| Comprensible | Que se entienda tanto el contenido como el funcionamiento. | Mensajes de error que dicen qué corregir; comportamiento previsible. |
| Robusto | Que funcione con distintos agentes de usuario y tecnologías de apoyo. | Marcado válido, uso correcto de roles y estados. |
El que más se pregunta es el segundo, porque el enunciado suele describirlo como «que los componentes y la navegación se puedan usar sin depender del ratón».
Y del lado de la generación de documentos, el supuesto de 2024 pedía producir un justificante en PDF: la biblioteca es iText, que existe tanto para Java como para .NET. Conviene reconocerla junto a las de ofimática —las de la Fundación Apache para hojas de cálculo y documentos de texto—, porque el distractor típico es ofrecer una de esas para un trabajo de PDF.
14. El mismo caso, escrito en las dos plataformas
El enunciado oficial pide «características, elementos, lenguajes y funciones en ambos entornos», y la forma honesta de cubrirlo es escribir lo mismo dos veces. El caso: publicar por HTTP el listado de alumnos de una base de datos, que es exactamente el supuesto que el tribunal ha puesto ya en dos convocatorias.
14.1. La entidad
Las dos plataformas parten de una clase que representa la fila. En el mundo Java se anota con las anotaciones de la especificación de persistencia:
@Entity
public class Alumno {
@Id @GeneratedValue
private Long id;
private String nombre;
private String apellido1;
// constructores, consultas y modificadores
}
Y en .NET la clase es una clase corriente, y es el contexto quien declara qué conjuntos hay:
public class Alumno {
public long Id { get; set; }
public string Nombre { get; set; }
public string Apellido1 { get; set; }
}
public class EducaContext : DbContext {
public DbSet<Alumno> Alumnos { get; set; }
}
La diferencia de estilo es real y conviene nombrarla: la plataforma Java tiende a anotar la propia clase, y la de Microsoft, a declarar la configuración en un sitio aparte. Las dos admiten los dos estilos, pero esa es la convención de cada una y es lo que hace reconocible un fragmento de código a simple vista.
14.2. El acceso a datos
En Java, con Spring, basta declarar una interfaz y el marco genera la implementación:
public interface AlumnoRepository extends JpaRepository<Alumno, Long> {
List<Alumno> findByApellido1Containing(String texto);
}
Lo llamativo de ese fragmento es que no hay implementación: el nombre del método es la consulta, y el marco la deduce y la traduce. Cuando la consulta no cabe en un nombre, se escribe en JPQL sobre la entidad.
En .NET la consulta se escribe con LINQ sobre el contexto, que es lo que el tribunal preguntó:
await context.Alumnos.Where(a => a.Apellido1.Contains(texto)).ToListAsync();
Las dos hacen lo mismo y las dos acaban en un SQL con una comparación de patrón. La diferencia de fondo: una declara la intención en el nombre y la otra la escribe como una expresión del lenguaje, que es lo que permite que el compilador la revise.
14.3. El punto de entrada HTTP
En Spring Boot, como ya se ha visto:
@RestController
public class AlumnoController {
@GetMapping("/alumnos")
public List<Alumno> obtenerAlumnos() {
return repository.findAll();
}
}
Y en ASP.NET Core, con un controlador de API:
[ApiController]
[Route("alumnos")]
public class AlumnoController : ControllerBase {
[HttpGet]
public async Task<IActionResult> ObtenerAlumnos() {
return Ok(await context.Alumnos.ToListAsync());
}
}
Las piezas se corresponden una a una y esa correspondencia es la que hay que llevar aprendida: una anotación marca la clase como controlador de datos; otra fija la ruta; otra fija el verbo; y el valor devuelto se convierte a JSON automáticamente. Cambian las palabras, no las ideas.
Un matiz que sí es distinto y que se pregunta: en la versión de .NET el método devuelve un resultado de acción, lo que permite elegir explícitamente el código de estado —el correcto, el de creado, el de no encontrado— en lugar de devolver siempre el mismo. En Spring esa elección se hace envolviendo el resultado en una entidad de respuesta cuando hace falta.
14.4. La seguridad del punto de entrada
Las dos plataformas declaran la seguridad en vez de programarla. En Spring se configura una cadena de filtros que dice qué rutas exigen qué rol, y en .NET se marca el controlador o el método con el atributo de autorización y se registra el intermediario correspondiente. En los dos casos el resultado es el mismo: quien no cumpla no llega al método, y el código del método no contiene una sola línea de comprobación.
Y en los dos casos el orden importa exactamente igual: si la comprobación se coloca después del enrutado que ya ejecutó la acción, no protege nada. Esa es la razón de que las dos plataformas insistan tanto en el orden de registro de sus intermediarios.
14.5. Las pruebas
La pieza que cierra el ejemplo, y que el tribunal metió en el mismo supuesto. En Java, con JUnit:
@Test
void devuelveTodos() {
assertEquals(3, service.obtenerAlumnos().size());
}
Y la comprobación de que un método lanza la excepción esperada, que ya se vio, con la afirmación que recibe la clase de la excepción y el fragmento como expresión lambda. En .NET el equivalente se escribe con la biblioteca de pruebas de la plataforma y con la misma estructura de tres pasos —preparar, actuar y comprobar—, que es universal y no depende del lenguaje.
🚨 En .NET esa biblioteca tiene nombre y el tribunal preguntó por su sintaxis exacta, no por la idea: pidió reconocer «la definición correcta de una clase de pruebas» con NUnit, y la respuesta era la que marca la clase con [TestFixture] y el método con [Test]:
[TestFixture]
public sealed class Tests {
[Test]
public void Test() { }
}
Los tres distractores mezclaban atributos que existen con otros que no, y la única defensa es tener la tabla en la cabeza:
| Atributo de NUnit | Qué marca | Equivalente en JUnit 5 |
|---|---|---|
| [TestFixture] | La clase que contiene pruebas. | No hace falta: basta con que la clase tenga métodos anotados. |
| [Test] | Un método de prueba sin parámetros. | @Test |
| [TestCase(…)] | Un método de prueba con los datos de entrada dentro del propio atributo: se repite una vez por cada juego. | @ParameterizedTest con @ValueSource o @CsvSource |
| [TestCaseSource] | Igual, pero los juegos de datos vienen de otro miembro que los genera. Marca el método, no la clase: ese era el error del cuarto distractor. | @MethodSource |
| [SetUp] y [TearDown] | Lo que se ejecuta antes y después de cada prueba. | @BeforeEach y @AfterEach |
| [OneTimeSetUp] y [OneTimeTearDown] | Una sola vez para toda la clase. | @BeforeAll y @AfterAll |
Y conviene saber que en .NET conviven tres bibliotecas de pruebas —NUnit, xUnit y MSTest—, mientras que en Java la respuesta es casi siempre JUnit. Si un enunciado nombra [Fact] en lugar de [Test], está hablando de xUnit y no de NUnit.
Conviene retener la tipología de pruebas, porque cae en el bloque III y se cruza con este tema: las unitarias prueban una pieza aislada; las de integración, cómo encajan varias; las de sistema, el conjunto completo; las de aceptación, que el usuario determina si vale; y las de regresión, que comprueban que los cambios sobre un componente no introducen errores en otros componentes no modificados. Esta última definición es literal de una pregunta oficial, y su distractor describía las pruebas de caja blanca como si miraran solo las entradas y las salidas, que es justo lo contrario: la caja blanca mira la estructura interna y la negra, solo lo que entra y lo que sale.
14.6. Qué se aprende al ponerlas una al lado de la otra
Tres conclusiones, y las tres sirven para contestar preguntas de comparación aunque no se hayan visto antes:
- Las capas son las mismas. Entidad, repositorio, servicio, controlador y configuración existen en las dos, con otro nombre a veces y con la misma responsabilidad siempre.
- Lo transversal se declara, no se programa. Transacciones, seguridad, trazas y validación se resuelven con anotaciones o atributos que el contenedor interpreta. Cuando en un examen aparezca código que comprueba permisos a mano dentro de un método, es sospechoso por definición.
- La diferencia real está en el ecosistema, no en la técnica. Se elige una plataforma por el personal que la conoce, por las licencias, por lo que ya hay desplegado y por la integración con el resto de sistemas del organismo. No por lo que puede hacer, porque las dos pueden hacer lo mismo.
15. El ciclo de vida de una petición, de punta a punta
Este apartado no está en ningún manual y es el que más rinde en el supuesto práctico, porque el tribunal no pregunta por una pieza aislada: describe una avería y pide el siguiente paso. Seguir una petición desde el navegador hasta la base de datos y de vuelta ordena todo lo anterior y da un método para diagnosticar.
15.1. Los once pasos
- El navegador resuelve el nombre del servidor y abre una conexión cifrada.
- La petición llega a un balanceador o a un servidor intermediario, que la reparte entre las instancias disponibles según lo que le diga el punto de salud de cada una.
- El servidor de aplicaciones —Tomcat, Kestrel— acepta la conexión y la entrega al canal de procesamiento.
- Los intermediarios o filtros transversales actúan en orden: trazas, compresión, comprobación de la conexión segura.
- La autenticación identifica al usuario a partir de la cookie de sesión o del testigo, y la autorización comprueba si su rol le permite lo que pide.
- El enrutado decide qué controlador y qué método atienden esa ruta y ese verbo.
- El controlador valida los datos de entrada y delega en un servicio: él no debería contener lógica de negocio.
- El servicio abre una transacción y llama al repositorio.
- El mapeador traduce las operaciones sobre objetos a SQL, lo envía por la conexión tomada del grupo y convierte el resultado en objetos.
- Al terminar el servicio, la transacción se confirma —o se deshace si algo ha fallado— y las modificaciones pendientes se escriben.
- El resultado se serializa a JSON, se le pone el código de estado que corresponde y la respuesta vuelve por el mismo canal, atravesando en sentido inverso todos los intermediarios.
15.2. Dónde falla cada cosa, y cómo se distingue
La utilidad del recorrido es que cada síntoma apunta a un tramo, y el orden en que se mira es el mismo que el de una avería de red: de fuera hacia dentro.
| Síntoma | Dónde mirar |
|---|---|
| El navegador no llega a conectar | Nombre, certificado, cortafuegos, puerto. Todavía no interviene la aplicación. |
| Responde el servidor pero con 404 | El enrutado: la ruta o el verbo no casan con ningún método. Es error del cliente, no avería. |
| 401 o 403 | Autenticación y autorización: sin identificar o identificado sin permiso. Son dos cosas distintas y el código lo dice. |
| 400 | Validación de entrada en el controlador: lo que llegó no cumple el contrato. |
| 500 | Avería real: excepción no controlada. Aquí es donde hay que leer las trazas, y donde debe existir un identificador de correlación para poder seguir esa petición concreta. |
| 503 | La aplicación no está disponible: no ha arrancado, no supera su punto de salud o el grupo de conexiones está agotado. |
| Todo funciona pero va lento | Casi siempre la capa de datos: consultas sin índice, carga perezosa que dispara cien consultas, o grupo de conexiones pequeño. Se confirma con el plan de ejecución y con las métricas. |
| Funciona en desarrollo y no en producción | Configuración por entorno: una variable que no está, una cadena de conexión distinta o un nivel de traza que oculta el error. |
15.3. Las tres capas, y por qué importan
El recorrido anterior atraviesa la arquitectura en capas que las dos plataformas suponen, y que conviene saber describir con sus responsabilidades:
- La capa de presentación —controladores, vistas o componentes de interfaz— recibe la interacción y presenta el resultado. No decide reglas de negocio ni sabe de tablas.
- La capa de negocio —los servicios— contiene las reglas y gobierna las transacciones. Es la única que debería cambiar cuando cambia la norma que regula el procedimiento.
- La capa de acceso a datos —repositorios y mapeador— sabe de persistencia y de nada más.
La regla que las mantiene útiles es que cada capa habla solo con la de debajo. Cuando un controlador escribe SQL o un repositorio decide una regla de negocio, la separación deja de existir y con ella todas sus ventajas: poder cambiar la interfaz sin tocar las reglas, poder probar la lógica sin levantar el servidor y poder sustituir la base de datos sin reescribir la aplicación.
Y la conexión con el resto del temario es directa: esa separación es la misma independencia de datos de la arquitectura de tres esquemas del bloque II, aplicada ahora al código en lugar de al modelo. Quien entienda una entiende la otra.
16. Cuadros para memorizar
16.1. Las equivalencias entre plataformas
| Java / Jakarta EE | .NET |
|---|---|
| JVM | CLR |
| Bytecode | CIL / MSIL |
| JIT | JIT |
| JDBC | ADO.NET |
| Jakarta Persistence | Entity Framework Core |
| JPQL | LINQ |
| Hibernate (proveedor) | El propio marco |
| Spring Boot | ASP.NET Core |
| Maven / pom.xml | NuGet |
| Tomcat | Kestrel / IIS |
| JUnit | xUnit |
| JavaFX / Android | .NET MAUI / WPF |
16.2. Los comandos y fragmentos que han caído
| Lo que se pide | La forma correcta |
|---|---|
| Ejecutar una aplicación Spring Boot | mvn spring-boot:run |
| Cambiar el número de versión | pom.xml |
| Controlador REST que devuelve una lista | @RestController y @GetMapping |
| Reiniciar Tomcat en Linux | systemctl restart tomcat9 |
| Código al parar el motor de Tomcat | LifecycleListener en el elemento del servidor |
| Conexión a la base de datos en Java | javax.naming y javax.sql |
| Método asíncrono en C# | async Task DevolverDato() |
| Consulta con filtro en Entity Framework | await … Where(…) … ToListAsync() |
| Traza informativa en .NET | logger.LogInformation("…") |
| Llamada REST desde el navegador | fetch(…).then(…).then(…) |
| Probar que salta una excepción | assertThrows(Clase.class, () -> …) |
16.3. Las definiciones literales
| Concepto | La frase que da por buena el tribunal |
|---|---|
| JIT | Compila el código intermedio a código máquina en tiempo de ejecución |
| CLR | Ejecuta el manejo de excepciones y la recolección de basura |
| .NET MAUI | Marco multiplataforma para aplicaciones móviles y de escritorio nativas con C# y XAML |
| ADO.NET | Componente de .NET para la comunicación con bases de datos |
| Jakarta Persistence | La homóloga funcional de Entity Framework Core |
| JPA | Una entidad es una tabla; cada instancia, una fila. Necesita proveedor. Su lenguaje es JPQL |
| PUT | Idempotente pero no seguro |
| Códigos 4xx | Error del cliente |
| JWT | La cabecera de autorización con Bearer y tres partes separadas por puntos |
| WS-Security | Con lo que se firman las peticiones de un servicio SOAP |
17. Lo que ya ha preguntado el tribunal
| Lo preguntado | Veces | La respuesta |
|---|---|---|
| Componente que compila el intermedio en ejecución | 2 | El JIT |
| Componente de .NET que maneja excepciones y recolecta basura | 2 | El CLR |
| Homóloga de Entity Framework Core en Jakarta EE | 1 | Jakarta Persistence |
| Qué es .NET MAUI | 2 | Marco multiplataforma con C# y XAML |
| Marco para escritorio nativo en .NET | 1 | .NET MAUI |
| Qué es ADO.NET | 1 | Componente para comunicación con bases de datos |
| Sobre Jakarta Persistence (JPA) | 2 | Entidad = tabla, instancia = fila |
| Paquetes Java para conectar a la base de datos | 1 | javax.naming y javax.sql |
| Controlador REST en Spring Boot | 2 | @RestController y @GetMapping |
| Ejecutar la aplicación Spring Boot | 2 | mvn spring-boot:run |
| Fichero donde se cambia la versión con Maven | 1 | pom.xml |
| Código de limpieza al parar Catalina | 2 | LifecycleListener en el elemento del servidor |
| Reiniciar Tomcat | 1 | systemctl restart tomcat9 |
| Método asíncrono en C# | 2 | async Task DevolverDato() |
| Consulta con filtro en .NET | 1 | await … Where(…) … ToListAsync() |
| Trazas en .NET | 2 | logger.LogInformation |
| Llamada REST desde JavaScript | 1 | fetch con dos encadenamientos |
| Probar una excepción con JUnit | 2 | assertThrows con lambda |
| Método idempotente pero no seguro | 1 | PUT |
| Clase de códigos de error del cliente | 2 | 4xx |
| Cabecera Authorization con Bearer | 1 | JWT |
| Firmar peticiones a un servicio SOAP | 1 | WS-Security |
Cómo estudiar este tema, en tres reglas. Primera: estudia las dos plataformas en paralelo, nunca por separado. El enunciado oficial pide compararlas y el tribunal pregunta correspondencias; con las dos columnas alineadas, media docena de preguntas se contestan sin pensar. Segunda: los comandos, escritos. Este tema aporta al supuesto práctico fragmentos de código con las cuatro opciones casi idénticas, y esa diferencia solo se cubre habiendo tecleado la orden: el nombre del complemento y el objetivo separados por dos puntos, la anotación exacta, la palabra que marca el método asíncrono. Y tercera: vigila los nombres que cambiaron —Java EE y Jakarta EE, javax y jakarta, .NET Framework y .NET—, porque el tribunal usa las dos formas y a veces la propia pregunta se apoya en esa historia.
Recuerda la aritmética del ejercicio: cada error descuenta un tercio y los blancos no penalizan. En las preguntas de código de este tema casi siempre hay dos opciones imposibles —un verbo inventado, una anotación que no existe, una palabra de más—, y con dos descartadas merece la pena arriesgar.
¿Te lo sabes? 🐂
Cien preguntas de este tema, escritas al estilo del cuestionario del INAP y contrastadas con los nueve exámenes oficiales que tenemos resueltos. Crea tu cuenta gratis para guardar tu progreso y repasar tus falladas. Gratis y siempre lo será.
