This is an automated email from the ASF dual-hosted git repository.

garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-codec.git


The following commit(s) were added to refs/heads/master by this push:
     new 077ba3d9 Add and use PhoneticEngine.Builder and deprecate old 
constructors.
077ba3d9 is described below

commit 077ba3d9e115dfa93b794c445dc2aba5f51b9650
Author: Gary Gregory <[email protected]>
AuthorDate: Thu Aug 6 10:56:39 2026 -0400

    Add and use PhoneticEngine.Builder and deprecate old constructors.
    
    - Javadoc
    - Ternary return
    - Formatting
---
 src/changes/changes.xml                            |   3 +-
 .../codec/language/bm/BeiderMorseEncoder.java      | 109 ++++-----
 .../commons/codec/language/bm/PhoneticEngine.java  | 106 ++++++++-
 .../language/bm/PhoneticEngineBuilderTest.java     | 251 +++++++++++++++++++++
 .../language/bm/PhoneticEnginePerformanceTest.java |   8 +-
 .../language/bm/PhoneticEngineRegressionTest.java  |  12 +-
 6 files changed, 411 insertions(+), 78 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 90046f49..f4445b73 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -43,10 +43,11 @@ The <action> type attribute can be add,update,fix,remove.
     <author>Apache Commons Developers</author>
   </properties>
   <body>
-    <release version="1.22.2" date="YYYY-MM-DD" description="This is a feature 
and maintenance release. Java 8 or later is required.">
+    <release version="1.23.0" date="YYYY-MM-DD" description="This is a feature 
and maintenance release. Java 8 or later is required.">
       <!-- FIX -->
       <action type="fix" dev="ggregory" due-to="Yu Bao, Gary Gregory">Optimize 
PhoneticEngine.encode(String, LanguageSet) for speed.</action>
       <!-- ADD -->
+      <action type="add" dev="ggregory" due-to="Gary Gregory">Add and use 
PhoneticEngine.Builder and deprecate old constructors.</action>
       <!-- UPDATE -->
     </release>
     <release version="1.22.1" date="2026-07-27" description="This is a feature 
and maintenance release. Java 8 or later is required.">
diff --git 
a/src/main/java/org/apache/commons/codec/language/bm/BeiderMorseEncoder.java 
b/src/main/java/org/apache/commons/codec/language/bm/BeiderMorseEncoder.java
index 58043771..1c2da755 100644
--- a/src/main/java/org/apache/commons/codec/language/bm/BeiderMorseEncoder.java
+++ b/src/main/java/org/apache/commons/codec/language/bm/BeiderMorseEncoder.java
@@ -23,50 +23,41 @@ import org.apache.commons.codec.StringEncoder;
 /**
  * Encodes strings into their Beider-Morse phonetic encoding.
  * <p>
- * Beider-Morse phonetic encodings are optimized for family names. However, 
they may be useful for a wide range of
- * words.
+ * Beider-Morse phonetic encodings are optimized for family names. However, 
they may be useful for a wide range of words.
  * </p>
  * <p>
- * This encoder is intentionally mutable to allow dynamic configuration 
through bean properties. As such, it is mutable,
- * and may not be thread-safe. If you require a guaranteed thread-safe 
encoding then use {@link PhoneticEngine}
- * directly.
+ * This encoder is intentionally mutable to allow dynamic configuration 
through bean properties. As such, it is mutable, and may not be thread-safe. If 
you
+ * require a guaranteed thread-safe encoding then use {@link PhoneticEngine} 
directly.
  * </p>
  * <h2>Encoding overview</h2>
  * <p>
- * Beider-Morse phonetic encodings is a multi-step process. Firstly, a table 
of rules is consulted to guess what
- * language the word comes from. For example, if it ends in "{@code ault}" 
then it infers that the word is French.
- * Next, the word is translated into a phonetic representation using a 
language-specific phonetics table. Some runs of
- * letters can be pronounced in multiple ways, and a single run of letters may 
be potentially broken up into phonemes at
- * different places, so this stage results in a set of possible 
language-specific phonetic representations. Lastly, this
- * language-specific phonetic representation is processed by a table of rules 
that re-writes it phonetically taking into
- * account systematic pronunciation differences between languages, to move it 
towards a pan-indo-european phonetic
- * representation. Again, sometimes there are multiple ways this could be done 
and sometimes things that can be
- * pronounced in several ways in the source language have only one way to 
represent them in this average phonetic
- * language, so the result is again a set of phonetic spellings.
+ * Beider-Morse phonetic encodings is a multi-step process. Firstly, a table 
of rules is consulted to guess what language the word comes from. For example, 
if
+ * it ends in "{@code ault}" then it infers that the word is French. Next, the 
word is translated into a phonetic representation using a language-specific
+ * phonetics table. Some runs of letters can be pronounced in multiple ways, 
and a single run of letters may be potentially broken up into phonemes at 
different
+ * places, so this stage results in a set of possible language-specific 
phonetic representations. Lastly, this language-specific phonetic 
representation is
+ * processed by a table of rules that re-writes it phonetically taking into 
account systematic pronunciation differences between languages, to move it 
towards a
+ * pan-indo-european phonetic representation. Again, sometimes there are 
multiple ways this could be done and sometimes things that can be pronounced in 
several
+ * ways in the source language have only one way to represent them in this 
average phonetic language, so the result is again a set of phonetic spellings.
  * </p>
  * <p>
- * Some names are treated as having multiple parts. This can be due to two 
things. Firstly, they may be hyphenated. In
- * this case, each individual hyphenated word is encoded, and then these are 
combined end-to-end for the final encoding.
- * Secondly, some names have standard prefixes, for example, "{@code Mac/Mc}" 
in Scottish (English) names. As
- * sometimes it is ambiguous whether the prefix is intended or is an accident 
of the spelling, the word is encoded once
- * with the prefix and once without it. The resulting encoding contains one 
and then the other result.
+ * Some names are treated as having multiple parts. This can be due to two 
things. Firstly, they may be hyphenated. In this case, each individual 
hyphenated
+ * word is encoded, and then these are combined end-to-end for the final 
encoding. Secondly, some names have standard prefixes, for example, "{@code 
Mac/Mc}" in
+ * Scottish (English) names. As sometimes it is ambiguous whether the prefix 
is intended or is an accident of the spelling, the word is encoded once with the
+ * prefix and once without it. The resulting encoding contains one and then 
the other result.
  * </p>
  * <h2>Encoding format</h2>
  * <p>
- * Individual phonetic spellings of an input word are represented in upper- 
and lower-case roman characters. Where there
- * are multiple possible phonetic representations, these are joined with a 
pipe ({@code |}) character. If multiple
- * hyphenated words where found, or if the word may contain a name prefix, 
each encoded word is placed in ellipses and
- * these blocks are then joined with hyphens. For example, "{@code d'ortley}" 
has a possible prefix. The form
- * without prefix encodes to "{@code ortlaj|ortlej}", while the form with 
prefix encodes to "
- * {@code dortlaj|dortlej}". Thus, the full, combined encoding is "{@code 
(ortlaj|ortlej)-(dortlaj|dortlej)}".
+ * Individual phonetic spellings of an input word are represented in upper- 
and lower-case roman characters. Where there are multiple possible phonetic
+ * representations, these are joined with a pipe ({@code |}) character. If 
multiple hyphenated words where found, or if the word may contain a name 
prefix, each
+ * encoded word is placed in ellipses and these blocks are then joined with 
hyphens. For example, "{@code d'ortley}" has a possible prefix. The form without
+ * prefix encodes to "{@code ortlaj|ortlej}", while the form with prefix 
encodes to " {@code dortlaj|dortlej}". Thus, the full, combined encoding is
+ * "{@code (ortlaj|ortlej)-(dortlaj|dortlej)}".
  * </p>
  * <p>
- * The encoded forms are often quite a bit longer than the input strings. This 
is because a single input may have many
- * potential phonetic interpretations. For example, "{@code Renault}" encodes 
to "
- * {@code rYnDlt|rYnalt|rYnult|rinDlt|rinalt|rinult}". The {@code APPROX} 
rules will tend to produce larger
- * encodings as they consider a wider range of possible, approximate phonetic 
interpretations of the original word.
- * Down-stream applications may wish to further process the encoding for 
indexing or lookup purposes, for example, by
- * splitting on pipe ({@code |}) and indexing under each of these alternatives.
+ * The encoded forms are often quite a bit longer than the input strings. This 
is because a single input may have many potential phonetic interpretations. For
+ * example, "{@code Renault}" encodes to " {@code 
rYnDlt|rYnalt|rYnult|rinDlt|rinalt|rinult}". The {@code APPROX} rules will tend 
to produce larger encodings as
+ * they consider a wider range of possible, approximate phonetic 
interpretations of the original word. Down-stream applications may wish to 
further process the
+ * encoding for indexing or lookup purposes, for example, by splitting on pipe 
({@code |}) and indexing under each of these alternatives.
  * </p>
  * <p>
  * <strong>Note</strong>: this version of the Beider-Morse encoding is 
equivalent with v3.4 of the reference implementation.
@@ -80,12 +71,11 @@ import org.apache.commons.codec.StringEncoder;
  * @since 1.6
  */
 public class BeiderMorseEncoder implements StringEncoder {
-
     // Implementation note: This class is a spring-friendly facade to 
PhoneticEngine. It allows read/write configuration
     // of an immutable PhoneticEngine instance that will be delegated to for 
the actual encoding.
 
     // a cached object
-    private PhoneticEngine engine = new PhoneticEngine(NameType.GENERIC, 
RuleType.APPROX, true);
+    private PhoneticEngine engine = PhoneticEngine.builder().get();
 
     /**
      * Constructs a new instance.
@@ -104,10 +94,7 @@ public class BeiderMorseEncoder implements StringEncoder {
 
     @Override
     public String encode(final String source) throws EncoderException {
-        if (source == null) {
-            return null;
-        }
-        return this.engine.encode(source);
+        return source != null ? engine.encode(source) : null;
     }
 
     /**
@@ -116,7 +103,7 @@ public class BeiderMorseEncoder implements StringEncoder {
      * @return The NameType currently being used.
      */
     public NameType getNameType() {
-        return this.engine.getNameType();
+        return engine.getNameType();
     }
 
     /**
@@ -125,71 +112,53 @@ public class BeiderMorseEncoder implements StringEncoder {
      * @return The RuleType currently being used.
      */
     public RuleType getRuleType() {
-        return this.engine.getRuleType();
+        return engine.getRuleType();
     }
 
     /**
-     * Discovers if multiple possible encodings are concatenated.
+     * Tests if multiple possible encodings are concatenated.
      *
      * @return true if multiple encodings are concatenated, false if just the 
first one is returned.
      */
     public boolean isConcat() {
-        return this.engine.isConcat();
+        return engine.isConcat();
     }
 
     /**
      * Sets how multiple possible phonetic encodings are combined.
      *
-     * @param concat
-     *            true if multiple encodings are to be combined with a '|', 
false if just the first one is
-     *            to be considered.
+     * @param concat true if multiple encodings are to be combined with a '|', 
false if just the first one is to be considered.
      */
     public void setConcat(final boolean concat) {
-        this.engine = new PhoneticEngine(this.engine.getNameType(),
-                                         this.engine.getRuleType(),
-                                         concat,
-                                         this.engine.getMaxPhonemes());
+        engine = 
PhoneticEngine.builder().setAll(engine).setConcat(concat).get();
     }
 
     /**
      * Sets the number of maximum of phonemes that shall be considered by the 
engine.
      *
-     * @param maxPhonemes
-     *            the maximum number of phonemes returned by the engine.
+     * @param maxPhonemes the maximum number of phonemes returned by the 
engine.
      * @since 1.7
      */
     public void setMaxPhonemes(final int maxPhonemes) {
-        this.engine = new PhoneticEngine(this.engine.getNameType(),
-                                         this.engine.getRuleType(),
-                                         this.engine.isConcat(),
-                                         maxPhonemes);
+        engine = 
PhoneticEngine.builder().setAll(engine).setMaxPhonemes(maxPhonemes).get();
     }
 
     /**
-     * Sets the type of name. Use {@link NameType#GENERIC} unless you 
specifically want phonetic encodings
-     * optimized for Ashkenazi or Sephardic Jewish family names.
+     * Sets the type of name. Use {@link NameType#GENERIC} unless you 
specifically want phonetic encodings optimized for Ashkenazi or Sephardic 
Jewish family
+     * names.
      *
-     * @param nameType
-     *            the NameType in use.
+     * @param nameType the NameType in use.
      */
     public void setNameType(final NameType nameType) {
-        this.engine = new PhoneticEngine(nameType,
-                                         this.engine.getRuleType(),
-                                         this.engine.isConcat(),
-                                         this.engine.getMaxPhonemes());
+        engine = 
PhoneticEngine.builder().setAll(engine).setNameType(nameType).get();
     }
 
     /**
      * Sets the rule type to apply. This will widen or narrow the range of 
phonetic encodings considered.
      *
-     * @param ruleType
-     *            {@link RuleType#APPROX} or {@link RuleType#EXACT} for 
approximate or exact phonetic matches.
+     * @param ruleType {@link RuleType#APPROX} or {@link RuleType#EXACT} for 
approximate or exact phonetic matches.
      */
     public void setRuleType(final RuleType ruleType) {
-        this.engine = new PhoneticEngine(this.engine.getNameType(),
-                                         ruleType,
-                                         this.engine.isConcat(),
-                                         this.engine.getMaxPhonemes());
+        engine = 
PhoneticEngine.builder().setAll(engine).setRuleType(ruleType).get();
     }
-
 }
diff --git 
a/src/main/java/org/apache/commons/codec/language/bm/PhoneticEngine.java 
b/src/main/java/org/apache/commons/codec/language/bm/PhoneticEngine.java
index f208a561..5e70ecfe 100644
--- a/src/main/java/org/apache/commons/codec/language/bm/PhoneticEngine.java
+++ b/src/main/java/org/apache/commons/codec/language/bm/PhoneticEngine.java
@@ -29,6 +29,7 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.TreeMap;
+import java.util.function.Supplier;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
@@ -55,8 +56,91 @@ import org.apache.commons.codec.language.bm.Rule.Phoneme;
 public class PhoneticEngine {
 
     /**
-     * Utility for manipulating a set of phonemes as they are being built up. 
Not intended for use outside this package, and probably not outside the
-     * {@link PhoneticEngine} class.
+     * Builder for a PhoneticEngine.
+     *
+     * @since 1.23.0
+     */
+    public static class Builder implements Supplier<PhoneticEngine> {
+
+        private NameType nameType = NameType.GENERIC;
+
+        private RuleType ruleType = RuleType.APPROX;
+
+        private boolean concat = true;
+
+        private int maxPhonemes = DEFAULT_MAX_PHONEMES;
+
+        private Builder() {
+            // empty
+        }
+
+        @Override
+        public PhoneticEngine get() {
+            return new PhoneticEngine(this);
+        }
+
+        /**
+         * Sets all the properties of this builder to match those of the given 
engine.
+         *
+         * @param engine The engine to copy properties from.
+         * @return This builder.
+         */
+        public Builder setAll(final PhoneticEngine engine) {
+            this.nameType = engine.getNameType();
+            this.ruleType = engine.getRuleType();
+            this.concat = engine.isConcat();
+            this.maxPhonemes = engine.getMaxPhonemes();
+            return this;
+        }
+
+        /**
+         * Sets whether the engine will concatenate multiple encodings.
+         *
+         * @param concat Whether the engine will concatenate multiple 
encodings.
+         * @return This builder.
+         */
+        public Builder setConcat(final boolean concat) {
+            this.concat = concat;
+            return this;
+        }
+
+        /**
+         * Sets maximum number of phonemes the engine will handle.
+         *
+         * @param maxPhonemes The maximum number of phonemes the engine will 
handle.
+         * @return This builder.
+         */
+        public Builder setMaxPhonemes(final int maxPhonemes) {
+            this.maxPhonemes = maxPhonemes;
+            return this;
+        }
+
+        /**
+         * Sets the name type for the engine to be built.
+         *
+         * @param nameType The type of names the engine will use.
+         * @return This builder.
+         */
+        public Builder setNameType(final NameType nameType) {
+            this.nameType = nameType;
+            return this;
+        }
+
+        /**
+         * Sets the rule type for the engine to be built.
+         *
+         * @param ruleType The type of rules the engine will use.
+         * @return This builder.
+         */
+        public Builder setRuleType(final RuleType ruleType) {
+            this.ruleType = ruleType;
+            return this;
+        }
+    }
+
+    /**
+     * Manipulates a set of phonemes as they are being built up. Not intended 
for use outside this package, and probably not outside the {@link 
PhoneticEngine}
+     * class.
      *
      * @since 1.6
      */
@@ -233,6 +317,16 @@ public class PhoneticEngine {
                 new HashSet<>(Arrays.asList("da", "dal", "de", "del", "dela", 
"de la", "della", "des", "di", "do", "dos", "du", "van", "von"))));
     }
 
+    /**
+     * Creates a new builder for a PhoneticEngine.
+     *
+     * @return a new builder for a PhoneticEngine.
+     * @since 1.23.0
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
     /**
      * Joins some strings with an internal separator.
      *
@@ -254,13 +348,19 @@ public class PhoneticEngine {
 
     private final int maxPhonemes;
 
+    private PhoneticEngine(final Builder builder) {
+        this(builder.nameType, builder.ruleType, builder.concat, 
builder.maxPhonemes);
+    }
+
     /**
      * Generates a new, fully-configured phonetic engine.
      *
      * @param nameType    the type of names it will use.
      * @param ruleType    the type of rules it will apply.
      * @param concatenate if it will concatenate multiple encodings.
+     * @deprecated Use {@link #builder()} instead.
      */
+    @Deprecated
     public PhoneticEngine(final NameType nameType, final RuleType ruleType, 
final boolean concatenate) {
         this(nameType, ruleType, concatenate, DEFAULT_MAX_PHONEMES);
     }
@@ -273,7 +373,9 @@ public class PhoneticEngine {
      * @param concatenate if it will concatenate multiple encodings.
      * @param maxPhonemes the maximum number of phonemes that will be handled.
      * @since 1.7
+     * @deprecated Use {@link #builder()} instead.
      */
+    @Deprecated
     public PhoneticEngine(final NameType nameType, final RuleType ruleType, 
final boolean concatenate, final int maxPhonemes) {
         if (ruleType == RuleType.RULES) {
             throw new IllegalArgumentException("ruleType must not be " + 
RuleType.RULES);
diff --git 
a/src/test/java/org/apache/commons/codec/language/bm/PhoneticEngineBuilderTest.java
 
b/src/test/java/org/apache/commons/codec/language/bm/PhoneticEngineBuilderTest.java
new file mode 100644
index 00000000..23cafb67
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/codec/language/bm/PhoneticEngineBuilderTest.java
@@ -0,0 +1,251 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.codec.language.bm;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link PhoneticEngine.Builder}.
+ *
+ * @since 1.23.0
+ */
+class PhoneticEngineBuilderTest {
+
+    /**
+     * Tests that the builder produces a non-null {@link PhoneticEngine}.
+     */
+    @Test
+    void testBuilderGet() {
+        final PhoneticEngine engine = PhoneticEngine.builder().get();
+        assertNotNull(engine);
+    }
+
+    /**
+     * Tests that {@link PhoneticEngine#builder()} returns a non-null builder.
+     */
+    @Test
+    void testBuilderNotNull() {
+        assertNotNull(PhoneticEngine.builder());
+    }
+
+    /**
+     * Tests that successive calls to {@link PhoneticEngine#builder()} return 
distinct builder instances.
+     */
+    @Test
+    void testBuilderReturnsNewInstance() {
+        assertNotSame(PhoneticEngine.builder(), PhoneticEngine.builder());
+    }
+
+    /**
+     * Tests the default values of the builder.
+     */
+    @Test
+    void testDefaultValues() {
+        final PhoneticEngine engine = PhoneticEngine.builder().get();
+        assertEquals(NameType.GENERIC, engine.getNameType());
+        assertEquals(RuleType.APPROX, engine.getRuleType());
+        assertTrue(engine.isConcat());
+        assertEquals(20, engine.getMaxPhonemes());
+    }
+
+    /**
+     * Tests that the builder produces engines that encode correctly 
(ASHKENAZI/APPROX/concat).
+     */
+    @Test
+    void testEngineEncodeAshkenaziApprox() {
+        // @formatter:off
+        final PhoneticEngine engine = PhoneticEngine.builder()
+                .setNameType(NameType.ASHKENAZI)
+                .setRuleType(RuleType.APPROX)
+                .setConcat(true)
+                .setMaxPhonemes(10)
+                .get();
+        // @formatter:on
+        final String result = engine.encode("Renault");
+        assertEquals("rYnDlt|rYnalt|rYnult|rinDlt|rinalt|rinolt|rinult", 
result);
+    }
+
+    /**
+     * Tests that the builder produces engines that encode correctly 
(GENERIC/APPROX/concat).
+     */
+    @Test
+    void testEngineEncodeGenericApprox() {
+        // @formatter:off
+        final PhoneticEngine engine = PhoneticEngine.builder()
+                .setNameType(NameType.GENERIC)
+                .setRuleType(RuleType.APPROX)
+                .setConcat(true)
+                .setMaxPhonemes(10)
+                .get();
+        // @formatter:on
+        final String result = engine.encode("Renault");
+        assertEquals("rinD|rinDlt|rina|rinalt|rino|rinolt|rinu|rinult", 
result);
+    }
+
+    /**
+     * Tests that the builder produces engines that encode correctly 
(GENERIC/EXACT/concat).
+     */
+    @Test
+    void testEngineEncodeGenericExact() {
+        // @formatter:off
+        final PhoneticEngine engine = PhoneticEngine.builder()
+                .setNameType(NameType.GENERIC)
+                .setRuleType(RuleType.EXACT)
+                .setConcat(true)
+                .setMaxPhonemes(10)
+                .get();
+        // @formatter:on
+        final String result = engine.encode("SntJohn-Smith");
+        assertEquals("sntjonsmit", result);
+    }
+
+    /**
+     * Tests that a builder-created engine is not the same instance when built 
twice.
+     */
+    @Test
+    void testGetReturnsDifferentInstances() {
+        final PhoneticEngine.Builder builder = PhoneticEngine.builder();
+        final PhoneticEngine engine1 = builder.get();
+        final PhoneticEngine engine2 = builder.get();
+        assertNotSame(engine1, engine2);
+    }
+
+    /**
+     * Tests method chaining: all setters return the same builder instance.
+     */
+    @Test
+    void testMethodChaining() {
+        // @formatter:off
+        final PhoneticEngine.Builder builder = PhoneticEngine.builder();
+        assertNotNull(builder
+                .setNameType(NameType.SEPHARDIC)
+                .setRuleType(RuleType.APPROX)
+                .setConcat(true)
+                .setMaxPhonemes(15)
+                .get());
+        // @formatter:on
+    }
+
+    /**
+     * Tests {@link PhoneticEngine.Builder#setAll(PhoneticEngine)} copies all 
properties.
+     */
+    @Test
+    void testSetAll() {
+        // @formatter:off
+        final PhoneticEngine original = PhoneticEngine.builder()
+                .setNameType(NameType.ASHKENAZI)
+                .setRuleType(RuleType.EXACT)
+                .setConcat(false)
+                .setMaxPhonemes(5)
+                .get();
+        // @formatter:on
+        final PhoneticEngine copy = 
PhoneticEngine.builder().setAll(original).get();
+        assertEquals(original.getNameType(), copy.getNameType());
+        assertEquals(original.getRuleType(), copy.getRuleType());
+        assertEquals(original.isConcat(), copy.isConcat());
+        assertEquals(original.getMaxPhonemes(), copy.getMaxPhonemes());
+    }
+
+    /**
+     * Tests {@link PhoneticEngine.Builder#setConcat(boolean)} with {@code 
false}.
+     */
+    @Test
+    void testSetConcatFalse() {
+        final PhoneticEngine engine = 
PhoneticEngine.builder().setConcat(false).get();
+        assertFalse(engine.isConcat());
+    }
+
+    /**
+     * Tests {@link PhoneticEngine.Builder#setConcat(boolean)} with {@code 
true}.
+     */
+    @Test
+    void testSetConcatTrue() {
+        final PhoneticEngine engine = 
PhoneticEngine.builder().setConcat(true).get();
+        assertTrue(engine.isConcat());
+    }
+
+    /**
+     * Tests {@link PhoneticEngine.Builder#setMaxPhonemes(int)}.
+     */
+    @Test
+    void testSetMaxPhonemes() {
+        final int maxPhonemes = 10;
+        final PhoneticEngine engine = 
PhoneticEngine.builder().setMaxPhonemes(maxPhonemes).get();
+        assertEquals(maxPhonemes, engine.getMaxPhonemes());
+    }
+
+    /**
+     * Tests {@link PhoneticEngine.Builder#setMaxPhonemes(int)} with {@link 
Integer#MAX_VALUE}.
+     */
+    @Test
+    void testSetMaxPhonemesMaxValue() {
+        final PhoneticEngine engine = 
PhoneticEngine.builder().setMaxPhonemes(Integer.MAX_VALUE).get();
+        assertEquals(Integer.MAX_VALUE, engine.getMaxPhonemes());
+    }
+
+    /**
+     * Tests {@link PhoneticEngine.Builder#setNameType(NameType)} with 
ASHKENAZI.
+     */
+    @Test
+    void testSetNameTypeAshkenazi() {
+        final PhoneticEngine engine = 
PhoneticEngine.builder().setNameType(NameType.ASHKENAZI).get();
+        assertEquals(NameType.ASHKENAZI, engine.getNameType());
+    }
+
+    /**
+     * Tests {@link PhoneticEngine.Builder#setNameType(NameType)}.
+     */
+    @Test
+    void testSetNameTypeGeneric() {
+        final PhoneticEngine engine = 
PhoneticEngine.builder().setNameType(NameType.GENERIC).get();
+        assertEquals(NameType.GENERIC, engine.getNameType());
+    }
+
+    /**
+     * Tests {@link PhoneticEngine.Builder#setNameType(NameType)} with 
SEPHARDIC.
+     */
+    @Test
+    void testSetNameTypeSephardic() {
+        final PhoneticEngine engine = 
PhoneticEngine.builder().setNameType(NameType.SEPHARDIC).get();
+        assertEquals(NameType.SEPHARDIC, engine.getNameType());
+    }
+
+    /**
+     * Tests {@link PhoneticEngine.Builder#setRuleType(RuleType)} with APPROX.
+     */
+    @Test
+    void testSetRuleTypeApprox() {
+        final PhoneticEngine engine = 
PhoneticEngine.builder().setRuleType(RuleType.APPROX).get();
+        assertEquals(RuleType.APPROX, engine.getRuleType());
+    }
+
+    /**
+     * Tests {@link PhoneticEngine.Builder#setRuleType(RuleType)} with EXACT.
+     */
+    @Test
+    void testSetRuleTypeExact() {
+        final PhoneticEngine engine = 
PhoneticEngine.builder().setRuleType(RuleType.EXACT).get();
+        assertEquals(RuleType.EXACT, engine.getRuleType());
+    }
+}
diff --git 
a/src/test/java/org/apache/commons/codec/language/bm/PhoneticEnginePerformanceTest.java
 
b/src/test/java/org/apache/commons/codec/language/bm/PhoneticEnginePerformanceTest.java
index 3f942187..5ec64a56 100644
--- 
a/src/test/java/org/apache/commons/codec/language/bm/PhoneticEnginePerformanceTest.java
+++ 
b/src/test/java/org/apache/commons/codec/language/bm/PhoneticEnginePerformanceTest.java
@@ -124,7 +124,13 @@ class PhoneticEnginePerformanceTest {
 
     @Test
     void test() {
-        final PhoneticEngine engine = new PhoneticEngine(NameType.GENERIC, 
RuleType.APPROX, true);
+        // @formatter:off
+        final PhoneticEngine engine = PhoneticEngine.builder()
+            .setNameType(NameType.GENERIC)
+            .setRuleType(RuleType.APPROX)
+            .setConcat(true)
+            .get();
+        // @formatter:on
         final String input = "Angelo";
         final long startMillis = System.currentTimeMillis();
         for (int i = 0; i < LOOP; i++) {
diff --git 
a/src/test/java/org/apache/commons/codec/language/bm/PhoneticEngineRegressionTest.java
 
b/src/test/java/org/apache/commons/codec/language/bm/PhoneticEngineRegressionTest.java
index 488ab3d0..0d598c55 100644
--- 
a/src/test/java/org/apache/commons/codec/language/bm/PhoneticEngineRegressionTest.java
+++ 
b/src/test/java/org/apache/commons/codec/language/bm/PhoneticEngineRegressionTest.java
@@ -42,9 +42,6 @@ class PhoneticEngineRegressionTest {
      * regressions in Commons-Codec.
      */
     private static String encode(final Map<String, String> args, final boolean 
concat, final String input) {
-        final Languages.LanguageSet languageSet;
-        final PhoneticEngine engine;
-
         // PhoneticEngine = NameType + RuleType + concat
         // we use common-codec's defaults: GENERIC + APPROX + true
         final String nameTypeArg = args.get("nameType");
@@ -53,9 +50,16 @@ class PhoneticEngineRegressionTest {
         final String ruleTypeArg = args.get("ruleType");
         final RuleType ruleType = ruleTypeArg == null ? RuleType.APPROX : 
RuleType.valueOf(ruleTypeArg);
 
-        engine = new PhoneticEngine(nameType, ruleType, concat);
+        // @formatter:off
+        final PhoneticEngine engine = PhoneticEngine.builder()
+            .setNameType(nameType)
+            .setRuleType(ruleType)
+            .setConcat(concat)
+            .get();
+        // @formatter:on
 
         // LanguageSet: defaults to automagic, otherwise a comma-separated 
list.
+        final Languages.LanguageSet languageSet;
         final String languageSetArg = args.get("languageSet");
         if (languageSetArg == null || languageSetArg.equals("auto")) {
             languageSet = null;

Reply via email to