Skip to content

Instantly share code, notes, and snippets.

@valarpirai
Last active January 16, 2026 06:56
Show Gist options
  • Select an option

  • Save valarpirai/7bcf5b1707b6188c6b86123798de8158 to your computer and use it in GitHub Desktop.

Select an option

Save valarpirai/7bcf5b1707b6188c6b86123798de8158 to your computer and use it in GitHub Desktop.
Error Handling code snippet
// ConfigController with proper error handling
import org.springframework.web.bind.annotation.*;
import org.springframework.http.*;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.dao.*;
import org.springframework.transaction.annotation.Transactional;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.validation.Valid;
import javax.validation.constraints.*;
import java.time.Instant;
import java.sql.Timestamp;
@RestController
@RequestMapping("/api/config")
public class ConfigController {
private final JdbcTemplate jdbcTemplate;
private final ObjectMapper objectMapper;
public ConfigController(JdbcTemplate jdbcTemplate, ObjectMapper objectMapper) {
this.jdbcTemplate = jdbcTemplate;
this.objectMapper = objectMapper;
}
@PostMapping("/enable")
public ResponseEntity<ApiResponse> enableConfig(@Valid @RequestBody ConfigRequest request) {
try {
// Validate input
validateRequest(request);
// Save to database with transaction
ConfigurationEntity savedConfig = saveConfiguration(request);
// Return success response
return ResponseEntity.ok(ApiResponse.success(
"Configuration updated successfully",
savedConfig
));
} catch (ValidationException e) {
// Input validation failed
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(ApiResponse.error(
"VALIDATION_ERROR",
"Invalid request: " + e.getMessage()
));
} catch (DuplicateKeyException e) {
// Configuration already exists
return ResponseEntity
.status(HttpStatus.CONFLICT)
.body(ApiResponse.error(
"DUPLICATE_CONFIG",
"Configuration for '" + request.getFeatureName() + "' already exists"
));
} catch (DataAccessException e) {
// Database error
System.err.println("Database error: " + e.getMessage());
e.printStackTrace();
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(ApiResponse.error(
"DATABASE_ERROR",
"Failed to save configuration. Please try again later."
));
} catch (Exception e) {
// Unexpected error
System.err.println("Unexpected error: " + e.getMessage());
e.printStackTrace();
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(ApiResponse.error(
"INTERNAL_ERROR",
"An unexpected error occurred"
));
}
}
private void validateRequest(ConfigRequest request) throws ValidationException {
if (request.getFeatureName() == null || request.getFeatureName().trim().isEmpty()) {
throw new ValidationException("Feature name is required");
}
if (request.getFeatureName().length() > 100) {
throw new ValidationException("Feature name must not exceed 100 characters");
}
if (request.getUpdatedBy() == null || request.getUpdatedBy().trim().isEmpty()) {
throw new ValidationException("Updated by is required");
}
// Validate feature name format (alphanumeric, underscores, hyphens)
if (!request.getFeatureName().matches("^[a-zA-Z0-9_-]+$")) {
throw new ValidationException(
"Feature name can only contain letters, numbers, underscores, and hyphens"
);
}
}
@Transactional
private ConfigurationEntity saveConfiguration(ConfigRequest request) {
String sql = """
INSERT INTO configurations (feature_name, enabled, updated_by, updated_at)
VALUES (?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
enabled = VALUES(enabled),
updated_by = VALUES(updated_by),
updated_at = VALUES(updated_at)
""";
Timestamp now = Timestamp.from(Instant.now());
try {
int rowsAffected = jdbcTemplate.update(
sql,
request.getFeatureName(),
request.isEnabled(),
request.getUpdatedBy(),
now
);
if (rowsAffected == 0) {
throw new DataAccessException("No rows were affected") {};
}
// Retrieve the saved configuration
return getConfiguration(request.getFeatureName());
} catch (DataAccessException e) {
// Log and rethrow
System.err.println("Failed to save configuration: " + e.getMessage());
throw e;
}
}
private ConfigurationEntity getConfiguration(String featureName) {
String sql = "SELECT * FROM configurations WHERE feature_name = ?";
return jdbcTemplate.queryForObject(sql, (rs, rowNum) -> {
ConfigurationEntity entity = new ConfigurationEntity();
entity.setId(rs.getLong("id"));
entity.setFeatureName(rs.getString("feature_name"));
entity.setEnabled(rs.getBoolean("enabled"));
entity.setUpdatedBy(rs.getString("updated_by"));
entity.setUpdatedAt(rs.getTimestamp("updated_at"));
return entity;
}, featureName);
}
// Exception handler for JSON parsing errors
@ExceptionHandler(JsonProcessingException.class)
public ResponseEntity<ApiResponse> handleJsonError(JsonProcessingException e) {
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(ApiResponse.error(
"INVALID_JSON",
"Invalid JSON format: " + e.getOriginalMessage()
));
}
// Request DTO
static class ConfigRequest {
@NotBlank(message = "Feature name is required")
@Size(max = 100, message = "Feature name must not exceed 100 characters")
private String featureName;
@NotNull(message = "Enabled flag is required")
private Boolean enabled;
@NotBlank(message = "Updated by is required")
private String updatedBy;
// Getters and setters
public String getFeatureName() { return featureName; }
public void setFeatureName(String featureName) { this.featureName = featureName; }
public Boolean isEnabled() { return enabled; }
public void setEnabled(Boolean enabled) { this.enabled = enabled; }
public String getUpdatedBy() { return updatedBy; }
public void setUpdatedBy(String updatedBy) { this.updatedBy = updatedBy; }
}
// Database entity
static class ConfigurationEntity {
private Long id;
private String featureName;
private Boolean enabled;
private String updatedBy;
private Timestamp updatedAt;
// Getters and setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getFeatureName() { return featureName; }
public void setFeatureName(String featureName) { this.featureName = featureName; }
public Boolean getEnabled() { return enabled; }
public void setEnabled(Boolean enabled) { this.enabled = enabled; }
public String getUpdatedBy() { return updatedBy; }
public void setUpdatedBy(String updatedBy) { this.updatedBy = updatedBy; }
public Timestamp getUpdatedAt() { return updatedAt; }
public void setUpdatedAt(Timestamp updatedAt) { this.updatedAt = updatedAt; }
}
// API Response wrapper
static class ApiResponse {
private boolean success;
private String message;
private String errorCode;
private Object data;
public static ApiResponse success(String message, Object data) {
ApiResponse response = new ApiResponse();
response.success = true;
response.message = message;
response.data = data;
return response;
}
public static ApiResponse error(String errorCode, String message) {
ApiResponse response = new ApiResponse();
response.success = false;
response.errorCode = errorCode;
response.message = message;
return response;
}
// Getters
public boolean isSuccess() { return success; }
public String getMessage() { return message; }
public String getErrorCode() { return errorCode; }
public Object getData() { return data; }
}
// Custom validation exception
static class ValidationException extends Exception {
public ValidationException(String message) {
super(message);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment