# 💥 StackOverflow y Dependencias Circulares en Java... ¡con ejemplos sabrosos!


¿Alguna vez tu app ha petado con un StackOverflowError
o con un error de dependencias circulares y te ha dejado con cara de 🫠?
Hoy vamos a ver cómo ocurren estos dos problemas, por qué a veces se mezclan, y lo mejor: cómo solucionarlos con ejemplos claros y simpáticos.
🔁 ¿Qué es una dependencia circular?
Una dependencia circular es cuando dos o más clases o componentes se necesitan mutuamente para funcionar, creando un bucle sin salida.
Ejemplo: tienes un ChefService
que necesita un DeliveryService
... pero este último también necesita al ChefService
.
@Service
public class ChefService {
public ChefService(DeliveryService deliveryService) {}
}
@Service
public class DeliveryService {
public DeliveryService(ChefService chefService) {}
}
Esto puede causar errores al iniciar la app (¡Spring se vuelve loco 😵!). Puedes evitarlo temporalmente con:
spring.main.allow-circular-references=true
🛑 Pero no lo uses como solución definitiva.
🧼 Soluciones reales a dependencias circulares
🧩 1. Usar interfaces
Introduce una interfaz intermedia para romper el acoplamiento:
public interface Deliverer {
void entregarPedido(String direccion);
}
@Service
public class ChefService {
private final Deliverer deliverer;
public ChefService(Deliverer deliverer) {
this.deliverer = deliverer;
}
}
@Service
public class DeliveryService implements Deliverer {
public void entregarPedido(String direccion) {
System.out.println("Entregando tacos a " + direccion);
}
}
¡Voilà! 🪄 Ahora ChefService
ya no depende directamente de DeliveryService
.
🕰️ 2. Inicialización Lazy
Si el problema solo ocurre al construir los objetos, puedes hacer esto:
@Autowired
@Lazy
private ChefService chefService;
📨 3. Eventos Spring (Arquitectura basada en eventos)
Rompe la dependencia usando eventos para comunicarte entre componentes:
@Component
public class PedidoListener {
@EventListener
public void onNuevoPedido(NuevoPedidoEvent event) {
System.out.println("Preparando pedido para: " + event.getDireccion());
}
}
🔥 ¿Y qué pasa con el StackOverflowError?
Un StackOverflowError
ocurre cuando una llamada recursiva nunca termina.
Peor aún si es debido a una relación bidireccional entre entidades como Tienda
y Producto
.
@Entity
public class Tienda {
@OneToMany(mappedBy = "tienda")
private List<Producto> productos;
}
@Entity
public class Producto {
@ManyToOne
private Tienda tienda;
}
Cuando quieres devolver un producto desde el endpoint...
@GetMapping("/productos")
public List<Producto> getProductos() {
return productoRepo.findAll();
}
😵 Hibernate entra en un bucle infinito al serializar:
Producto → Tienda → Productos → Tienda → Productos... ¡Boom! 💥 Stack overflow.
✅ ¿Cómo lo resolvemos?
🛠️ Usando un DTO (Data Transfer Object)
public class ProductoDTO {
private String nombre;
private double precio;
private String tiendaNombre;
}
@GetMapping("/productos")
public List<ProductoDTO> getProductos() {
return productoRepo.findAll().stream()
.map(p -> new ProductoDTO(p.getNombre(), p.getPrecio(), p.getTienda().getNombre()))
.toList();
}
Ahora solo serializamos lo necesario. 🙌 ¡Adiós recursión infinita!
🧠 Conclusión
Circular dependencies y stack overflows son como los "ex" del código: difíciles de manejar y mejor evitarlos 😅
Pero si los detectas a tiempo y aplicas buenas prácticas como:
- Uso de interfaces
- Arquitectura basada en eventos
- Inicialización perezosa
- DTOs
✨ Tu aplicación será más sana, escalable y menos propensa a "romperse sola".
¡Feliz codificación y cero círculos viciosos! 🚀
Subscribe to my newsletter
Read articles from Carlos Exposito directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
