Worked example — interface in domain, implementation in infrastructure.
Below, the only thing the domain knows is the interface. The Postgres adapter implements it from outside, so the domain never imports JDBC:
// === src/main/java/com/shop/domain/OrderRepository.java ===
package com.shop.domain;
public interface OrderRepository {
Order findById(OrderId id);
void save(Order order);
}
// === src/main/java/com/shop/infrastructure/PostgresOrderRepository.java ===
package com.shop.infrastructure;
import com.shop.domain.Order;
import com.shop.domain.OrderId;
import com.shop.domain.OrderRepository;
import javax.sql.DataSource;
public class PostgresOrderRepository implements OrderRepository {
private final DataSource ds;
public PostgresOrderRepository(DataSource ds) {
this.ds = ds;
}
@Override
public Order findById(OrderId id) { /* SQL here */ return null; }
@Override
public void save(Order order) { /* SQL here */ }
}
Check the import direction: infrastructure imports from domain. No file under domain/ imports from infrastructure/. That's the whole rule.