diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/phonetic/PhoneticEncoderEnum.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/phonetic/PhoneticEncoderEnum.java
index 92eb96c9944..3675af5e9fc 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/phonetic/PhoneticEncoderEnum.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/phonetic/PhoneticEncoderEnum.java
@@ -20,6 +20,7 @@ package ca.uhn.fhir.context.phonetic;
* #L%
*/
+import ca.uhn.fhir.util.PhoneticEncoderUtil;
import org.apache.commons.codec.language.Caverphone1;
import org.apache.commons.codec.language.Caverphone2;
import org.apache.commons.codec.language.ColognePhonetic;
@@ -38,16 +39,30 @@ public enum PhoneticEncoderEnum {
MATCH_RATING_APPROACH(new ApacheEncoder("MATCH_RATING_APPROACH", new MatchRatingApproachEncoder())),
METAPHONE(new ApacheEncoder("METAPHONE", new Metaphone())),
NYSIIS(new ApacheEncoder("NYSIIS", new Nysiis())),
+ NYSIIS_LONG(new ApacheEncoder("NYSIIS_LONG", new Nysiis(false))),
REFINED_SOUNDEX(new ApacheEncoder("REFINED_SOUNDEX", new RefinedSoundex())),
SOUNDEX(new ApacheEncoder("SOUNDEX", new Soundex())),
NUMERIC(new NumericEncoder());
private final IPhoneticEncoder myPhoneticEncoder;
+ /**
+ * Do not construct this enum via constructor.
+ *
+ * Use {@link PhoneticEncoderUtil} instead.
+ */
+ @Deprecated
PhoneticEncoderEnum(IPhoneticEncoder thePhoneticEncoder) {
myPhoneticEncoder = thePhoneticEncoder;
}
+ /**
+ * Use PhoneticEncoderWrapper.getEncoderWrapper(PhoneticEncoderEnum.name())
+ *
+ * This is a deprecated method of getting the encoder (as they
+ * are static across the server and non-configurable).
+ */
+ @Deprecated
public IPhoneticEncoder getPhoneticEncoder() {
return myPhoneticEncoder;
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/PhoneticEncoderUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/PhoneticEncoderUtil.java
new file mode 100644
index 00000000000..4274b273262
--- /dev/null
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/PhoneticEncoderUtil.java
@@ -0,0 +1,171 @@
+package ca.uhn.fhir.util;
+
+import ca.uhn.fhir.context.phonetic.ApacheEncoder;
+import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
+import ca.uhn.fhir.context.phonetic.NumericEncoder;
+import ca.uhn.fhir.context.phonetic.PhoneticEncoderEnum;
+import org.apache.commons.codec.language.Caverphone1;
+import org.apache.commons.codec.language.Caverphone2;
+import org.apache.commons.codec.language.ColognePhonetic;
+import org.apache.commons.codec.language.DoubleMetaphone;
+import org.apache.commons.codec.language.MatchRatingApproachEncoder;
+import org.apache.commons.codec.language.Metaphone;
+import org.apache.commons.codec.language.Nysiis;
+import org.apache.commons.codec.language.RefinedSoundex;
+import org.apache.commons.codec.language.Soundex;
+import org.apache.commons.lang3.EnumUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class PhoneticEncoderUtil {
+
+ // embedded class only for parameter returns
+ private static class ParsedValues {
+ private final Integer maxCodeLength;
+ private final String encoderString;
+
+ public ParsedValues(String theString, Integer theMaxCode) {
+ maxCodeLength = theMaxCode;
+ encoderString = theString;
+ }
+
+ public Integer getMaxCodeLength() {
+ return maxCodeLength;
+ }
+
+ public String getEncoderString() {
+ return encoderString;
+ }
+ }
+
+ private static final Logger ourLog = LoggerFactory.getLogger(PhoneticEncoderUtil.class);
+
+ private PhoneticEncoderUtil() {
+ }
+
+ /**
+ * Creates the phonetic encoder wrapper from
+ * an input string.
+ *
+ *
+ * String must be in the format of...
+ *
+ *
+ * PhoneticEncoderEnum(MAX_LENGTH)
+ *
+ * @return The IPhoneticEncoder
+ */
+ public static IPhoneticEncoder getEncoder(String theString) {
+ ParsedValues values = parseIntValue(theString);
+ String encoderType = values.getEncoderString();
+ Integer encoderMaxString = values.getMaxCodeLength();
+
+ IPhoneticEncoder encoder = getEncoderFromString(encoderType, encoderMaxString);
+ if (encoder != null) {
+ return encoder;
+ }
+ else {
+ ourLog.warn("Invalid phonetic param string " + theString);
+ return null;
+ }
+ }
+
+ private static ParsedValues parseIntValue(String theString) {
+ String encoderType = null;
+ Integer encoderMaxString = null;
+
+ int braceIndex = theString.indexOf("(");
+ if (braceIndex != -1) {
+ int len = theString.length();
+ if (theString.charAt(len - 1) == ')') {
+ encoderType = theString.substring(0, braceIndex);
+ String num = theString.substring(braceIndex + 1, len - 1);
+ try {
+ encoderMaxString = Integer.parseInt(num);
+ } catch (NumberFormatException ex) {
+ // invalid number parse error
+ }
+
+ if (encoderMaxString == null
+ || encoderMaxString < 0) {
+ // parse error
+ ourLog.error("Invalid encoder max character length: " + num);
+ encoderType = null;
+ }
+ }
+ // else - parse error
+ }
+ else {
+ encoderType = theString;
+ }
+
+ return new ParsedValues(encoderType, encoderMaxString);
+ }
+
+ private static IPhoneticEncoder getEncoderFromString(String theName, Integer theMax) {
+ IPhoneticEncoder encoder = null;
+ PhoneticEncoderEnum enumVal = EnumUtils.getEnum(PhoneticEncoderEnum.class, theName);
+
+ if (enumVal != null) {
+ switch (enumVal) {
+ case CAVERPHONE1:
+ Caverphone1 caverphone1 = new Caverphone1();
+ encoder = new ApacheEncoder(theName, caverphone1);
+ break;
+ case CAVERPHONE2:
+ Caverphone2 caverphone2 = new Caverphone2();
+ encoder = new ApacheEncoder(theName, caverphone2);
+ break;
+ case COLOGNE:
+ ColognePhonetic colognePhonetic = new ColognePhonetic();
+ encoder = new ApacheEncoder(theName, colognePhonetic);
+ break;
+ case DOUBLE_METAPHONE:
+ DoubleMetaphone doubleMetaphone = new DoubleMetaphone();
+ if (theMax != null) {
+ doubleMetaphone.setMaxCodeLen(theMax);
+ }
+ encoder = new ApacheEncoder(theName, doubleMetaphone);
+ break;
+ case MATCH_RATING_APPROACH:
+ MatchRatingApproachEncoder matchRatingApproachEncoder = new MatchRatingApproachEncoder();
+ encoder = new ApacheEncoder(theName, matchRatingApproachEncoder);
+ break;
+ case METAPHONE:
+ Metaphone metaphone = new Metaphone();
+ if (theMax != null) {
+ metaphone.setMaxCodeLen(theMax);
+ }
+ encoder = new ApacheEncoder(theName, metaphone);
+ break;
+ case NYSIIS:
+ Nysiis nysiis = new Nysiis();
+ encoder = new ApacheEncoder(theName, nysiis);
+ break;
+ case NYSIIS_LONG:
+ Nysiis nysiis1_long = new Nysiis(false);
+ encoder = new ApacheEncoder(theName, nysiis1_long);
+ break;
+ case REFINED_SOUNDEX:
+ RefinedSoundex refinedSoundex = new RefinedSoundex();
+ encoder = new ApacheEncoder(theName, refinedSoundex);
+ break;
+ case SOUNDEX:
+ Soundex soundex = new Soundex();
+ // soundex has deprecated setting the max size
+ encoder = new ApacheEncoder(theName, soundex);
+ break;
+ case NUMERIC:
+ encoder = new NumericEncoder();
+ break;
+ default:
+ // we don't ever expect to be here
+ // this log message is purely for devs who update this
+ // enum, but not this method
+ ourLog.error("Unhandled PhoneticParamEnum value " + enumVal.name());
+ break;
+ }
+ }
+ return encoder;
+ }
+}
diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/context/phonetic/PhoneticEncoderTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/context/phonetic/PhoneticEncoderTest.java
index e43327eb818..a2082c5258a 100644
--- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/context/phonetic/PhoneticEncoderTest.java
+++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/context/phonetic/PhoneticEncoderTest.java
@@ -1,5 +1,7 @@
package ca.uhn.fhir.context.phonetic;
+import ca.uhn.fhir.util.PhoneticEncoderUtil;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.slf4j.Logger;
@@ -10,7 +12,7 @@ import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.jupiter.api.Assertions.assertEquals;
-class PhoneticEncoderTest {
+public class PhoneticEncoderTest {
private static final Logger ourLog = LoggerFactory.getLogger(PhoneticEncoderTest.class);
private static final String NUMBER = "123";
@@ -21,7 +23,9 @@ class PhoneticEncoderTest {
@ParameterizedTest
@EnumSource(PhoneticEncoderEnum.class)
public void testEncodeAddress(PhoneticEncoderEnum thePhoneticEncoderEnum) {
- String encoded = thePhoneticEncoderEnum.getPhoneticEncoder().encode(ADDRESS_LINE);
+ IPhoneticEncoder encoder = PhoneticEncoderUtil.getEncoder(thePhoneticEncoderEnum.name());
+ Assertions.assertNotNull(encoder);
+ String encoded = encoder.encode(ADDRESS_LINE);
ourLog.info("{}: {}", thePhoneticEncoderEnum.name(), encoded);
if (thePhoneticEncoderEnum == PhoneticEncoderEnum.NUMERIC) {
assertEquals(NUMBER + SUITE, encoded);
diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/PhoneticEncoderUtilTests.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/PhoneticEncoderUtilTests.java
new file mode 100644
index 00000000000..b862a51e966
--- /dev/null
+++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/PhoneticEncoderUtilTests.java
@@ -0,0 +1,150 @@
+package ca.uhn.fhir.util;
+
+import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
+import ca.uhn.fhir.context.phonetic.PhoneticEncoderEnum;
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class PhoneticEncoderUtilTests {
+
+ private final Logger myLogger = (Logger) LoggerFactory.getLogger(PhoneticEncoderUtil.class);
+
+ private ListAppender myListAppender;
+
+ @BeforeEach
+ public void init() {
+ myListAppender = Mockito.mock(ListAppender.class);
+ myLogger.addAppender(myListAppender);
+ }
+
+ @Test
+ public void getEncoder_withNumberProvided_parsesOutCorrectValue() {
+ int num = 5;
+ PhoneticEncoderEnum enumVal = PhoneticEncoderEnum.DOUBLE_METAPHONE;
+ String enumString = enumVal.name() + "(" + num + ")";
+
+ // test
+ IPhoneticEncoder encoder = PhoneticEncoderUtil.getEncoder(enumString);
+
+ assertNotNull(encoder);
+ assertEquals(enumVal.name(), encoder.name());
+ }
+
+ @Test
+ public void getEncoder_withNoNumber_parsesOutCorrectValue() {
+ // test
+ for (PhoneticEncoderEnum enumVal : PhoneticEncoderEnum.values()) {
+ IPhoneticEncoder encoder = PhoneticEncoderUtil.getEncoder(enumVal.name());
+
+ assertNotNull(encoder);
+ assertEquals(enumVal.name(), encoder.name());
+ }
+ }
+
+ @Test
+ public void getEncoder_withInvalidNumber_returnsNullAndLogs() {
+ // setup
+ myLogger.setLevel(Level.ERROR);
+ String num = "A";
+
+ // test
+ IPhoneticEncoder encoder = PhoneticEncoderUtil.getEncoder(
+ PhoneticEncoderEnum.METAPHONE.name() + "(" + num + ")"
+ );
+
+ // verify
+ assertNull(encoder);
+ ArgumentCaptor loggingCaptor = ArgumentCaptor.forClass(ILoggingEvent.class);
+ Mockito.verify(myListAppender).doAppend(loggingCaptor.capture());
+ assertEquals(1, loggingCaptor.getAllValues().size());
+ ILoggingEvent event = loggingCaptor.getValue();
+ assertEquals("Invalid encoder max character length: " + num,
+ event.getMessage());
+ }
+
+ @Test
+ public void getEncoder_unknownValue_returnsNull() {
+ // setup
+ myLogger.setLevel(Level.WARN);
+ String theString = "Not a valid encoder value";
+
+ IPhoneticEncoder encoder = PhoneticEncoderUtil.getEncoder(theString);
+
+ // verify
+ assertNull(encoder);
+ ArgumentCaptor captor = ArgumentCaptor.forClass(ILoggingEvent.class);
+ Mockito.verify(myListAppender)
+ .doAppend(captor.capture());
+ assertEquals(1, captor.getAllValues().size());
+ ILoggingEvent event = captor.getValue();
+ assertEquals("Invalid phonetic param string " + theString,
+ event.getMessage());
+ }
+
+ @Test
+ public void getEncoder_emptyNumberValue_returnsNull() {
+ myLogger.setLevel(Level.ERROR);
+
+ // test
+ IPhoneticEncoder encoder = PhoneticEncoderUtil.getEncoder(PhoneticEncoderEnum.METAPHONE.name() + "()");
+
+ verifyOutcome_getEncoder_NumberParseFailure(encoder, "");
+ }
+
+ @Test
+ public void getEncoder_invalidNumberValue_returnsNull() {
+ myLogger.setLevel(Level.ERROR);
+
+ // test
+ String num = "-1";
+ IPhoneticEncoder encoder = PhoneticEncoderUtil.getEncoder(PhoneticEncoderEnum.METAPHONE.name() + "(" + num + ")");
+
+ verifyOutcome_getEncoder_NumberParseFailure(encoder, num);
+ }
+
+ @Test
+ public void getEncoder_incorrectBrackets_returnsNull() {
+ myLogger.setLevel(Level.ERROR);
+
+ // test
+ String num = "(";
+ IPhoneticEncoder encoder = PhoneticEncoderUtil.getEncoder(PhoneticEncoderEnum.METAPHONE.name() + "(" + num + ")");
+
+ verifyOutcome_getEncoder_NumberParseFailure(encoder, num);
+ }
+
+ @Test
+ public void getEncoder_maxInt_returnsWrapper() {
+ // test
+ IPhoneticEncoder encoder = PhoneticEncoderUtil.getEncoder(
+ PhoneticEncoderEnum.METAPHONE.name() + "(" + Integer.MAX_VALUE + ")"
+ );
+
+ assertNotNull(encoder);
+ assertEquals(PhoneticEncoderEnum.METAPHONE.name(), encoder.name());
+ }
+
+ /**
+ * Verifies the outcome encoder when an invalid string was passed in.
+ */
+ private void verifyOutcome_getEncoder_NumberParseFailure(IPhoneticEncoder theEncoder, String theNumberParam) {
+ assertNull(theEncoder);
+ ArgumentCaptor loggingCaptor = ArgumentCaptor.forClass(ILoggingEvent.class);
+ Mockito.verify(myListAppender).doAppend(loggingCaptor.capture());
+ assertEquals(1, loggingCaptor.getAllValues().size());
+ ILoggingEvent event = loggingCaptor.getValue();
+ assertEquals("Invalid encoder max character length: " + theNumberParam,
+ event.getMessage());
+ }
+}
diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_7_0/3335-added-configuration-to-specify-max-code-lengths.yml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_7_0/3335-added-configuration-to-specify-max-code-lengths.yml
new file mode 100644
index 00000000000..fc016ce453e
--- /dev/null
+++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_7_0/3335-added-configuration-to-specify-max-code-lengths.yml
@@ -0,0 +1,14 @@
+---
+type: add
+issue: 3335
+jira: 3603
+title: "Added ability to specify max code lengths for supported
+ Phonetic Encoders (Metaphone, Double_Metaphone).
+ To specify max code length, append the code length to the searchparameter-phonetic-encoder
+ extension in brackets after the encoder type.
+ eg:
+ {
+ \"url\": \"http://hapifhir.io/fhir/StructureDefinition/searchparameter-phonetic-encoder\",
+ \"valueString\": \"METAPHONE(5)\"
+ }
+ "
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchCustomSearchParamTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchCustomSearchParamTest.java
index b1a2d997fe5..eae49d8734b 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchCustomSearchParamTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchCustomSearchParamTest.java
@@ -1,6 +1,7 @@
package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.context.RuntimeSearchParam;
+import ca.uhn.fhir.context.phonetic.PhoneticEncoderEnum;
import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IAnonymousInterceptor;
import ca.uhn.fhir.interceptor.api.Pointcut;
@@ -10,6 +11,7 @@ import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
+import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.DateParam;
@@ -20,6 +22,7 @@ import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
+import ca.uhn.fhir.util.HapiExtensions;
import org.hamcrest.Matchers;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Appointment;
@@ -53,6 +56,7 @@ import org.hl7.fhir.r4.model.ServiceRequest;
import org.hl7.fhir.r4.model.Specimen;
import org.hl7.fhir.r4.model.StringType;
import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -77,6 +81,7 @@ import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
@@ -197,6 +202,60 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
assertEquals(0, search.size());
}
+ @Test
+ public void testCreatePhoneticSearchParameterWithOptionalCharacterLength() {
+ String testString = "Richard Smith";
+ int modifiedLength = 7;
+
+ // create 2 different search parameters
+ // same encoder, but different lengths
+ SearchParameter searchParam = constructSearchParameter();
+ searchParam.setCode("fuzzydefault");
+ searchParam.addExtension()
+ .setUrl(HapiExtensions.EXT_SEARCHPARAM_PHONETIC_ENCODER)
+ .setValue(new StringType(PhoneticEncoderEnum.METAPHONE.name()));
+
+ mySearchParameterDao.create(searchParam, mySrd);
+ mySearchParamRegistry.forceRefresh();
+
+ SearchParameter searchParamModified = constructSearchParameter();
+ searchParamModified.setCode("fuzzymodified");
+ searchParamModified.addExtension()
+ .setUrl(HapiExtensions.EXT_SEARCHPARAM_PHONETIC_ENCODER)
+ .setValue(new StringType(PhoneticEncoderEnum.METAPHONE.name() + "(" + modifiedLength + ")"));
+
+ mySearchParameterDao.create(searchParamModified, mySrd);
+ mySearchParamRegistry.forceRefresh();
+
+ // check the 2 parameters are different
+ // when fetched from the system
+ RuntimeSearchParam paramdefault = mySearchParamRegistry.getActiveSearchParam("Patient",
+ "fuzzydefault");
+ RuntimeSearchParam parammodified = mySearchParamRegistry.getActiveSearchParam("Patient",
+ "fuzzymodified");
+
+ // verify the encoders are different!
+ assertNotEquals(paramdefault, parammodified);
+ String encodedDefault = paramdefault.encode(testString);
+ String encodedMod = parammodified.encode(testString);
+ assertEquals(modifiedLength, encodedMod.length());
+ assertNotEquals(encodedDefault.length(), encodedMod.length());
+ }
+
+ /**
+ * Constructs a search parameter for patients on name.
+ * No code or extentions are set
+ * (so the calling test should set these).
+ */
+ private SearchParameter constructSearchParameter() {
+ SearchParameter sp = new SearchParameter();
+ sp.addBase("Patient");
+ sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
+ sp.setType(Enumerations.SearchParamType.STRING);
+ sp.setExpression("Patient.name.given.first() + ' ' + Patient.name.family");
+ return sp;
+ }
+
/**
* Draft search parameters should be ok even if they aren't completely valid
*/
@@ -299,7 +358,6 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
}
}
-
@Test
@Disabled
public void testCreateInvalidParamInvalidResourceName() {
diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/registry/SearchParameterCanonicalizer.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/registry/SearchParameterCanonicalizer.java
index f2262e28475..65ecc8d9017 100644
--- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/registry/SearchParameterCanonicalizer.java
+++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/registry/SearchParameterCanonicalizer.java
@@ -23,14 +23,14 @@ package ca.uhn.fhir.jpa.searchparam.registry;
import ca.uhn.fhir.context.ComboSearchParamType;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeSearchParam;
-import ca.uhn.fhir.context.phonetic.PhoneticEncoderEnum;
+import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.util.DatatypeUtil;
import ca.uhn.fhir.util.FhirTerser;
import ca.uhn.fhir.util.HapiExtensions;
-import org.apache.commons.lang3.EnumUtils;
+import ca.uhn.fhir.util.PhoneticEncoderUtil;
import org.hl7.fhir.dstu3.model.Extension;
import org.hl7.fhir.dstu3.model.SearchParameter;
import org.hl7.fhir.instance.model.api.IBase;
@@ -374,10 +374,15 @@ public class SearchParameterCanonicalizer {
private void setEncoder(RuntimeSearchParam theRuntimeSearchParam, IBaseDatatype theValue) {
if (theValue instanceof IPrimitiveType) {
String stringValue = ((IPrimitiveType>) theValue).getValueAsString();
- PhoneticEncoderEnum encoderEnum = EnumUtils.getEnum(PhoneticEncoderEnum.class, stringValue);
- if (encoderEnum != null) {
- theRuntimeSearchParam.setPhoneticEncoder(encoderEnum.getPhoneticEncoder());
- } else {
+
+ // every string creates a completely new encoder wrapper.
+ // this is fine, because the runtime search parameters are constructed at startup
+ // for every saved value
+ IPhoneticEncoder encoder = PhoneticEncoderUtil.getEncoder(stringValue);
+ if (encoder != null) {
+ theRuntimeSearchParam.setPhoneticEncoder(encoder);
+ }
+ else {
ourLog.error("Invalid PhoneticEncoderEnum value '" + stringValue + "'");
}
}
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/PhoneticEncoderMatcher.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/PhoneticEncoderMatcher.java
index c63cee5eaa2..cf008d86e14 100644
--- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/PhoneticEncoderMatcher.java
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/PhoneticEncoderMatcher.java
@@ -22,6 +22,7 @@ package ca.uhn.fhir.mdm.rules.matcher;
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
import ca.uhn.fhir.context.phonetic.PhoneticEncoderEnum;
+import ca.uhn.fhir.util.PhoneticEncoderUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -31,7 +32,7 @@ public class PhoneticEncoderMatcher implements IMdmStringMatcher {
private final IPhoneticEncoder myStringEncoder;
public PhoneticEncoderMatcher(PhoneticEncoderEnum thePhoneticEnum) {
- myStringEncoder = thePhoneticEnum.getPhoneticEncoder();
+ myStringEncoder = PhoneticEncoderUtil.getEncoder(thePhoneticEnum.name());
}
@Override