Java Framework Protection Mechanisms

Java Framework Protection Mechanisms

Java's strong typing and enterprise frameworks provide robust SQL injection defenses:

// Spring Data JPA - Repository pattern with automatic security
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    // Method name queries - automatically safe
    List<User> findByStatusAndCreatedAfter(String status, LocalDateTime date);
    
    // JPQL with named parameters
    @Query("SELECT u FROM User u WHERE u.email LIKE %:email% AND u.role IN :roles")
    List<User> searchUsers(@Param("email") String email, @Param("roles") List<String> roles);
    
    // Native SQL with indexed parameters
    @Query(value = "SELECT * FROM users WHERE department_id = ?1 AND salary > ?2", 
           nativeQuery = true)
    List<User> findByDepartmentAndSalary(Long departmentId, BigDecimal minSalary);
    
    // Complex dynamic queries using Specifications
    default List<User> findByComplexCriteria(UserSearchCriteria criteria) {
        return findAll((root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            
            if (criteria.getName() != null) {
                predicates.add(criteriaBuilder.like(
                    root.get("name"), 
                    "%" + criteria.getName() + "%"
                ));
            }
            
            if (criteria.getMinAge() != null) {
                predicates.add(criteriaBuilder.greaterThanOrEqualTo(
                    root.get("age"), 
                    criteria.getMinAge()
                ));
            }
            
            if (criteria.getRoles() != null && !criteria.getRoles().isEmpty()) {
                predicates.add(root.get("role").in(criteria.getRoles()));
            }
            
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
    }
}

// MyBatis with type-safe queries
@Mapper
public interface ProductMapper {
    // Automatic parameter binding with #{} syntax
    @Select("SELECT * FROM products WHERE category_id = #{categoryId} AND price > #{minPrice}")
    List<Product> findByCategoryAndPrice(@Param("categoryId") Long categoryId, 
                                        @Param("minPrice") BigDecimal minPrice);
    
    // Dynamic SQL with safety
    @SelectProvider(type = ProductSqlProvider.class, method = "buildFindByExample")
    List<Product> findByExample(ProductExample example);
}

public class ProductSqlProvider {
    public String buildFindByExample(ProductExample example) {
        return new SQL() {{
            SELECT("*");
            FROM("products");
            
            if (example.getName() != null) {
                WHERE("name LIKE #{name}");
            }
            if (example.getMinPrice() != null) {
                WHERE("price >= #{minPrice}");
            }
            if (example.getCategories() != null && !example.getCategories().isEmpty()) {
                WHERE("category_id IN (" +
                    example.getCategories().stream()
                        .map(c -> "#{categories[" + example.getCategories().indexOf(c) + "]}")
                        .collect(Collectors.joining(",")) +
                ")");
            }
            ORDER_BY("created_at DESC");
        }}.toString();
    }
}