8 Must‑Use Spring Boot Code Snippets to Stop Re‑inventing the Wheel
This article presents eight ready‑to‑use Spring Boot 3.5.0 code snippets—including MapStruct converters, embeddable collections, i18n helpers, secure random generators, custom runtime exceptions, type‑safe configuration properties, JPA auditing, and custom validation annotations—each illustrated with concrete examples and runnable code.
Introduction
If you have worked on multiple Spring Boot projects, you have probably rewritten the same string‑handling logic, error‑handling utilities, or localization helpers again and again. Building a reusable component library can dramatically improve development efficiency and keep code style consistent.
1. Powerful MapStruct type conversion
MapStruct can map DTOs to entities, but basic type conversion is often ignored. The article shows how to centralise String‑to‑List and List‑to‑String conversion in a mapper.
public class MyDto { private String name; private String tags; }</code>
<code>public class MyEntity { private String name; private List<String> tags; } @Mapper(componentModel = "spring")
public interface CommonMapper {
@Named("stringToList")
default List<String> stringToList(String source) {
if (!StringUtils.hasText(source)) return new ArrayList<>();
return Arrays.stream(source.split(","))
.map(String::trim)
.filter(StringUtils::hasText)
.collect(Collectors.toList());
}
@Named("listToString")
default String listToString(List<String> source) {
if (source == null || source.isEmpty()) return "";
return String.join(",", source);
}
}Usage in a service demonstrates the conversion results:
@Service
public class CommonService {
private final CommonMapper commonMapper;
public CommonService(CommonMapper commonMapper) { this.commonMapper = commonMapper; }
public void action() {
List<String> list = commonMapper.stringToList("a, b, c");
System.err.println(list);
String str = commonMapper.listToString(Arrays.asList("x", "y", "z"));
System.err.println(str);
}
} [a, b, c]
x,y,z2. Embedded collection usage
When a simple tag list or email list does not warrant a separate association table, an @Embeddable combined with a JPA AttributeConverter can store a Set<String> in a single column.
@Embeddable
public class EmailEmbeddable {
private String value;
public EmailEmbeddable() {}
public EmailEmbeddable(Set<String> values) {
if (values == null) { this.value = null; }
else {
Set<String> validated = values.stream()
.filter(StringUtils::hasText)
.map(String::trim)
.collect(Collectors.toSet());
this.value = String.join(",", validated);
}
}
public Set<String> getValues() {
if (!StringUtils.hasText(value)) return new HashSet<>();
return Arrays.stream(value.split(","))
.map(String::trim)
.filter(StringUtils::hasText)
.collect(Collectors.toSet());
}
} @Entity
@Table(name = "x_customer")
public class Customer {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@Embedded
private EmailEmbeddable emails;
}The resulting table (illustrated in the original image) stores the email set in a single column.
3. Internationalization helper
Injecting MessageSource in every service and handling LocaleContextHolder manually is cumbersome. A static‑or‑bean‑based helper simplifies i18n.
@Component
public class MessageHelper {
private final MessageSource messageSource;
public MessageHelper(MessageSource messageSource) { this.messageSource = messageSource; }
public String getMessage(String code, Object... args) {
return messageSource.getMessage(code, args, LocaleContextHolder.getLocale());
}
public String getMessageOrDefault(String code, String defaultMsg, Object... args) {
return messageSource.getMessage(code, args, defaultMsg, LocaleContextHolder.getLocale());
}
}4. Secure random string generator
For temporary passwords, reference numbers or API tokens, a generator based on SecureRandom provides cryptographic safety.
@Component
public class RandomUtil {
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
private static final String ALPHANUMERIC = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
public static String generateReference(int length) {
StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; i++) {
sb.append(ALPHANUMERIC.charAt(SECURE_RANDOM.nextInt(ALPHANUMERIC.length())));
}
return sb.toString();
}
public static String generateToken() {
byte[] randomBytes = new byte[24];
SECURE_RANDOM.nextBytes(randomBytes);
return Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes);
}
}5. Domain‑specific runtime exceptions
Creating a hierarchy of runtime exceptions allows @ControllerAdvice to return precise HTTP status codes.
// 404 – resource not found
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String resourceName, String fieldName, Object fieldValue) {
super(String.format("%s not found with %s : '%s'", resourceName, fieldName, fieldValue));
}
}
// 409 – duplicate resource
public class DuplicateResourceException extends RuntimeException {
public DuplicateResourceException(String message) { super(message); }
} @Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
public User getUserById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("User", "id", id));
}
public User createUser(User user) {
if (userRepository.existsByEmail(user.getEmail())) {
throw new DuplicateResourceException("Email already registered: " + user.getEmail());
}
return userRepository.save(user);
}
} @RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleResourceNotFound(ResourceNotFoundException ex) {
ErrorResponse error = new ErrorResponse("NOT_FOUND", ex.getMessage(), LocalDateTime.now());
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}
@ExceptionHandler(DuplicateResourceException.class)
public ResponseEntity<ErrorResponse> handleDuplicateResource(DuplicateResourceException ex) {
ErrorResponse error = new ErrorResponse("CONFLICT", ex.getMessage(), LocalDateTime.now());
return new ResponseEntity<>(error, HttpStatus.CONFLICT);
}
}6. Type‑safe configuration properties
Instead of using primitive int or long for timeouts and file sizes, Spring Boot’s @ConfigurationProperties supports Duration and DataSize, making application.yml self‑documenting.
@Configuration
@ConfigurationProperties(prefix = "pack.app.upload")
public class UploadConfig {
private Duration timeout = Duration.ofSeconds(30);
private DataSize maxFileSize = DataSize.ofMegabytes(10);
} pack:
app:
upload:
timeout: 10s
maxFileSize: 10MB7. Automatic auditing
Using a @MappedSuperclass with @CreatedDate, @LastModifiedDate, @CreatedBy and @LastModifiedBy lets JPA automatically populate audit fields.
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class AuditValue {
@CreatedDate @Column(updatable = false) protected LocalDateTime createdAt;
@LastModifiedDate protected LocalDateTime modifiedAt;
@CreatedBy @Column(updatable = false) protected String createdBy;
@LastModifiedBy protected String modifiedBy;
} @Entity @Table(name = "t_name")
public class Product extends AuditValue { } @Configuration
@EnableJpaAuditing(auditorAwareRef = "auditorAware")
public class JpaConfig {
@Bean
public AuditorAware<String> auditorAware() {
// In a real project obtain the user from SecurityContext
return () -> Optional.of("SYSTEM");
}
}8. Annotation‑based custom validation
Spring’s built‑in @Valid constraints sometimes lack the needed expressiveness. A custom @ValueOfEnum annotation validates that a String matches a specific enum.
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = ValueOfEnumValidator.class)
public @interface ValueOfEnum {
Class<? extends Enum<?>> enumClass();
String message() default "must be a valid {enumClass} value";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
} public class ValueOfEnumValidator implements ConstraintValidator<ValueOfEnum, CharSequence> {
private List<String> acceptedValues;
@Override
public void initialize(ValueOfEnum annotation) {
acceptedValues = Stream.of(annotation.enumClass().getEnumConstants())
.map(Enum::name)
.collect(Collectors.toList());
}
@Override
public boolean isValid(CharSequence value, ConstraintValidatorContext context) {
if (value == null) return true; // let @NotNull handle nulls
return acceptedValues.contains(value.toString().toUpperCase());
}
} @ValueOfEnum(enumClass = OrderStatus.class, message = "Invalid status")
private String status;Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
