Skip to content

Implement singleton pattern for SimpleMessageFormatter #450

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/main/java/am/ik/yavi/builder/ValidatorBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,8 @@ public Validator<T> build() {
return new Validator<>(messageKeySeparator,
new PredicatesList<>(this.conflictStrategy, this.predicatesList).toList(), this.collectionValidators,
this.conditionalValidators,
this.messageFormatter == null ? new SimpleMessageFormatter() : this.messageFormatter, this.failFast);
this.messageFormatter == null ? SimpleMessageFormatter.getInstance() : this.messageFormatter,
this.failFast);
}

/**
Expand Down
24 changes: 24 additions & 0 deletions src/main/java/am/ik/yavi/message/SimpleMessageFormatter.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,32 @@
import java.text.MessageFormat;
import java.util.Locale;

/**
* A simple implementation of {@link MessageFormatter} that formats messages using
* {@link MessageFormat}. This class is a singleton to optimize resource usage.
*/
public class SimpleMessageFormatter implements MessageFormatter {

private static final SimpleMessageFormatter INSTANCE = new SimpleMessageFormatter();

/**
* Returns the singleton instance of {@link SimpleMessageFormatter}.
* @return the singleton instance
*/
public static SimpleMessageFormatter getInstance() {
return INSTANCE;
}

/**
* Constructor.
* @deprecated Use {@link #getInstance()} instead to get the singleton instance. This
* constructor will be removed in a future version.
*/
@Deprecated
public SimpleMessageFormatter() {
// Public constructor kept for backward compatibility
}

@Override
public String format(String messageKey, String defaultMessageFormat, Object[] args, Locale locale) {
return new MessageFormat(defaultMessageFormat, locale).format(args);
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/am/ik/yavi/core/BiConsumerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class BiConsumerTest {

static final ErrorHandler<List<ConstraintViolation>> errorHandler = (errors, name, messageKey, args,
defaultMessage) -> errors.add(new ConstraintViolation(name, messageKey, defaultMessage, args,
new SimpleMessageFormatter(), Locale.ENGLISH));
SimpleMessageFormatter.getInstance(), Locale.ENGLISH));

static final Validator<User> userValidator = ValidatorBuilder.of(User.class)
.constraint(User::getName, "name", c -> c.notNull().greaterThanOrEqual(1).lessThanOrEqual(20))
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/am/ik/yavi/core/BiValidatorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class BiValidatorTest {

static final ErrorHandler<List<ConstraintViolation>> errorHandler = (errors, name, messageKey, args,
defaultMessage) -> errors.add(new ConstraintViolation(name, messageKey, defaultMessage, args,
new SimpleMessageFormatter(), Locale.ENGLISH));
SimpleMessageFormatter.getInstance(), Locale.ENGLISH));

static final Validator<User> userValidator = ValidatorBuilder.of(User.class)
.constraint(User::getName, "name", c -> c.notNull().greaterThanOrEqual(1).lessThanOrEqual(20))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class ConstraintViolationsExceptionTest {
@Test
void customMessage() {
final ConstraintViolations violations = new ConstraintViolations();
final SimpleMessageFormatter messageFormatter = new SimpleMessageFormatter();
final SimpleMessageFormatter messageFormatter = SimpleMessageFormatter.getInstance();
violations.add(new ConstraintViolation("name1", "key", "{0} is invalid.", new Object[] { "a" },
messageFormatter, Locale.ENGLISH));
final ConstraintViolationsException exception = new ConstraintViolationsException("error!", violations);
Expand All @@ -38,7 +38,7 @@ void customMessage() {
@Test
void defaultMessage() {
final ConstraintViolations violations = new ConstraintViolations();
final SimpleMessageFormatter messageFormatter = new SimpleMessageFormatter();
final SimpleMessageFormatter messageFormatter = SimpleMessageFormatter.getInstance();
violations.add(new ConstraintViolation("name1", "key", "{0} is invalid.", new Object[] { "a" },
messageFormatter, Locale.ENGLISH));
final ConstraintViolationsException exception = new ConstraintViolationsException(violations);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class ConstraintViolationsTest {

@Test
public void apply() {
SimpleMessageFormatter messageFormatter = new SimpleMessageFormatter();
SimpleMessageFormatter messageFormatter = SimpleMessageFormatter.getInstance();
ConstraintViolations violations = new ConstraintViolations();
violations.add(new ConstraintViolation("foo0", "abc0", "hello0", new Object[] { 1 }, messageFormatter,
Locale.getDefault()));
Expand Down
4 changes: 2 additions & 2 deletions src/test/java/am/ik/yavi/core/ValidatedTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ void successWith() {
void failureWith() {
final Validated<Object> validated = Validated
.failureWith(new ConstraintViolation("name", "notNull", "\"{0}\" must not be blank.",
new Object[] { "name", "" }, new SimpleMessageFormatter(), Locale.ENGLISH));
new Object[] { "name", "" }, SimpleMessageFormatter.getInstance(), Locale.ENGLISH));
assertThat(validated.isValid()).isFalse();
assertThat(validated.errors()).hasSize(1);
assertThat(validated.errors().get(0).message()).isEqualTo("\"name\" must not be blank.");
Expand All @@ -48,7 +48,7 @@ void failureWith() {
void testFailureWith() {
final Validated<Object> validated = Validated.failureWith(
Collections.singletonList(new ConstraintViolation("name", "notNull", "\"{0}\" must not be blank.",
new Object[] { "name", "" }, new SimpleMessageFormatter(), Locale.ENGLISH)));
new Object[] { "name", "" }, SimpleMessageFormatter.getInstance(), Locale.ENGLISH)));
assertThat(validated.isValid()).isFalse();
assertThat(validated.errors()).hasSize(1);
assertThat(validated.errors().get(0).message()).isEqualTo("\"name\" must not be blank.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class BiConsumerFactoryTest {

private final ErrorHandler<List<ConstraintViolation>> errorHandler = (errors, name, messageKey, args,
defaultMessage) -> errors.add(new ConstraintViolation(name, messageKey, defaultMessage, args,
new SimpleMessageFormatter(), Locale.ENGLISH));
SimpleMessageFormatter.getInstance(), Locale.ENGLISH));

private final BiConsumerFactory<List<ConstraintViolation>> validatorFactory = new BiConsumerFactory<>(
this.errorHandler);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class BiValidatorFactoryTest {

private final ErrorHandler<List<ConstraintViolation>> errorHandler = (errors, name, messageKey, args,
defaultMessage) -> errors.add(new ConstraintViolation(name, messageKey, defaultMessage, args,
new SimpleMessageFormatter(), Locale.ENGLISH));
SimpleMessageFormatter.getInstance(), Locale.ENGLISH));

private final BiValidatorFactory<List<ConstraintViolation>> validatorFactory = new BiValidatorFactory<>(
this.errorHandler);
Expand Down