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

Carlos ExpositoCarlos Exposito
3 min read

¿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! 🚀

0
Subscribe to my newsletter

Read articles from Carlos Exposito directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Carlos Exposito
Carlos Exposito