diff --git a/openml-h2o/src/main/java/com/feedzai/openml/h2o/H2OAlgorithm.java b/openml-h2o/src/main/java/com/feedzai/openml/h2o/H2OAlgorithm.java
index 61e75053..897af1ec 100644
--- a/openml-h2o/src/main/java/com/feedzai/openml/h2o/H2OAlgorithm.java
+++ b/openml-h2o/src/main/java/com/feedzai/openml/h2o/H2OAlgorithm.java
@@ -95,8 +95,6 @@ public enum H2OAlgorithm implements MLAlgorithmEnum {
/**
* Generalized Linear Models (GLM) estimate regression models for outcomes following exponential distributions.
- *
- * We enforce it to always have a family parameter Binomial that causes it to be a classification algorithm.
*/
GENERALIZED_LINEAR_MODEL(createDescriptor(
"Generalized Linear Modeling",
diff --git a/openml-h2o/src/main/java/com/feedzai/openml/h2o/algos/H2OGeneralizedLinearModelUtils.java b/openml-h2o/src/main/java/com/feedzai/openml/h2o/algos/H2OGeneralizedLinearModelUtils.java
index 94430ad8..a1cd1661 100644
--- a/openml-h2o/src/main/java/com/feedzai/openml/h2o/algos/H2OGeneralizedLinearModelUtils.java
+++ b/openml-h2o/src/main/java/com/feedzai/openml/h2o/algos/H2OGeneralizedLinearModelUtils.java
@@ -65,7 +65,8 @@ public final class H2OGeneralizedLinearModelUtils extends AbstractSupervisedH2OA
// H2O UI excludes these in a hard-coded way...so do we.
.filter(modelParameter -> !"tweedie_link_power".equals(modelParameter.getName()) &&
!"tweedie_variance_power".equals(modelParameter.getName()) &&
- !"nlambdas".equals(modelParameter.getName()) && !"early_stopping".equals(modelParameter.getName())
+ !"nlambdas".equals(modelParameter.getName()) && !"early_stopping".equals(modelParameter.getName()) &&
+ !"influence".equals(modelParameter.getName())
)
.collect(Collectors.toSet());
diff --git a/openml-h2o/src/main/java/com/feedzai/openml/h2o/params/ParametersBuilderUtil.java b/openml-h2o/src/main/java/com/feedzai/openml/h2o/params/ParametersBuilderUtil.java
index 0ac1d95d..ca900d05 100644
--- a/openml-h2o/src/main/java/com/feedzai/openml/h2o/params/ParametersBuilderUtil.java
+++ b/openml-h2o/src/main/java/com/feedzai/openml/h2o/params/ParametersBuilderUtil.java
@@ -243,7 +243,29 @@ private static ModelParameter getModelParameter(final Class extends water.bind
if (apiAnnot.values().length > 0) {
final Set possibleValues = Arrays.stream(apiAnnot.values()).collect(Collectors.toSet());
final Enum> defaultValue = getDefaultChoiceValue(paramsClass, fieldName);
- paramType = new ChoiceFieldType(possibleValues, defaultValue.name());
+ String defaultValueName = defaultValue != null ? defaultValue.name() : "";
+ if (!possibleValues.contains(defaultValueName)) {
+ final String finalDefaultName = defaultValueName;
+
+ // Check if there is a match
+ final Optional match = possibleValues.stream()
+ .filter(val -> val.equalsIgnoreCase(finalDefaultName))
+ .findFirst();
+
+ if (match.isPresent()) {
+ defaultValueName = match.get();
+ } else if (!possibleValues.isEmpty()) {
+ // Fallback to the first allowed choice if the default is missing or null
+ defaultValueName = possibleValues.iterator().next();
+ logger.warn(
+ "Default value name `{}` is not present on possible values set `{}`. Falling back to `{}`",
+ finalDefaultName,
+ possibleValues,
+ defaultValueName
+ );
+ }
+ }
+ paramType = new ChoiceFieldType(possibleValues, defaultValueName);
} else if (fieldType.equals(String.class)) {
final String defaultValue = getDefaultStringValue(paramsClass, fieldName);
diff --git a/openml-h2o/src/test/java/com/feedzai/openml/h2o/H2OAlgorithmTestParams.java b/openml-h2o/src/test/java/com/feedzai/openml/h2o/H2OAlgorithmTestParams.java
index b01ea281..552f98e5 100644
--- a/openml-h2o/src/test/java/com/feedzai/openml/h2o/H2OAlgorithmTestParams.java
+++ b/openml-h2o/src/test/java/com/feedzai/openml/h2o/H2OAlgorithmTestParams.java
@@ -133,7 +133,9 @@ public static Map getGlm() {
.put("lambda", "1")
.put("lambda_search", "true")
.put("standardize", "true")
- .put("non_negative", "true")
+ // non_negative does not work with multinomial/ordinal families and GLM
+ // fails on init if set to true (see https://github.com/h2oai/h2o-3/issues/7055)
+ .put("non_negative", "false")
.put("obj_reg", "-1")
.put("theta", "1e-10") // default value
.put("HGLM", "false") // default value
diff --git a/openml-h2o/src/test/java/com/feedzai/openml/h2o/algos/ParametersTest.java b/openml-h2o/src/test/java/com/feedzai/openml/h2o/algos/ParametersTest.java
index 39a743d2..99f16fe4 100644
--- a/openml-h2o/src/test/java/com/feedzai/openml/h2o/algos/ParametersTest.java
+++ b/openml-h2o/src/test/java/com/feedzai/openml/h2o/algos/ParametersTest.java
@@ -32,6 +32,8 @@
import com.feedzai.openml.h2o.algos.mocks.RegularParameters;
import com.feedzai.openml.h2o.params.ParametersBuilderUtil;
import com.feedzai.openml.provider.descriptor.ModelParameter;
+import com.feedzai.openml.provider.descriptor.fieldtype.ChoiceFieldType;
+
import org.junit.Test;
import org.slf4j.LoggerFactory;
@@ -177,4 +179,96 @@ private ListAppender appendLogger(final Class> clazz) {
classLogger.addAppender(listAppender);
return listAppender;
}
+
+ /**
+ * Tests that a case-mismatched enum name is still resolved.
+ */
+ @Test
+ public void choiceFieldCaseMismatchCorrection() {
+ final Set parameters = ParametersBuilderUtil.getParametersFor(
+ MockCaseMismatchSchema.class,
+ MockCaseMismatchBinding.class
+ );
+
+ assertThat(parameters).as("The choice parameter descriptor should be resolved successfully").hasSize(1);
+
+ final ModelParameter parameter = parameters.iterator().next();
+
+ assertThat(parameter.getName()).as("The parameter name should match the target field").isEqualTo("dummyField");
+
+ final ChoiceFieldType fieldType = (ChoiceFieldType) parameter.getFieldType();
+
+ assertThat(fieldType.getDefaultValue()).as("The enum 'VALUE_ONE' should match the schema's 'value_one' choice")
+ .isEqualTo("value_one");
+ }
+
+ /**
+ * Tests that when an enum field evaluates to null or does not match any valid choices, we fall back to the first
+ * available choice.
+ */
+ @Test
+ public void choiceFieldNullOrMissingFallback() {
+ final ListAppender listAppender = appendLogger(ParametersBuilderUtil.class);
+
+ final Set parameters = ParametersBuilderUtil.getParametersFor(
+ MockFallbackSchema.class,
+ MockFallbackBinding.class
+ );
+
+ assertThat(parameters).as("The parameter descriptor should be built using a fallback strategy").hasSize(1);
+
+ final ModelParameter parameter = parameters.iterator().next();
+
+ assertThat(parameter.getName()).as("The parameter name should match the target field").isEqualTo("dummyField");
+
+ final ChoiceFieldType fieldType = (ChoiceFieldType) parameter.getFieldType();
+
+ assertThat(fieldType.getDefaultValue()).as(
+ "A null value should fall back safely to the first choice in the schema").isEqualTo("value_one");
+
+ final List loggingList = listAppender.list;
+ assertThat(loggingList).as("A fallback must log an explicit warning").isNotEmpty();
+
+ final ILoggingEvent warningEvent = loggingList.get(0);
+ assertThat(warningEvent.getLevel()).isEqualTo(Level.WARN);
+ assertThat(warningEvent.getMessage()).as("The warning message should detail the fallback replacement")
+ .containsIgnoringCase("is not present on possible values set");
+ }
+
+ /**
+ * Dummy enum to simulate parameter choices.
+ */
+ public enum DummyEnum {
+ VALUE_ONE, VALUE_TWO;
+ }
+
+ /**
+ * Schema where the annotation choices are lowercase.
+ */
+ public static class MockCaseMismatchSchema extends water.api.schemas3.ModelParametersSchemaV3 {
+ @water.api.API(help = "Case mismatch", values = {"value_one", "value_two"})
+ public DummyEnum dummyField;
+ }
+
+ /**
+ * Fallback schema to be used when client binding POJO is null.
+ */
+ public static class MockFallbackSchema extends water.api.schemas3.ModelParametersSchemaV3 {
+ @water.api.API(help = "Fallback", values = {"value_one"})
+ public DummyEnum dummyField;
+ }
+
+ /**
+ * Client binding POJO where the runtime field resolves to uppercase.
+ */
+ public static class MockCaseMismatchBinding extends water.bindings.pojos.ModelParametersSchemaV3 {
+ public DummyEnum dummyField = DummyEnum.VALUE_ONE;
+ }
+
+ /**
+ * Client binding POJO where the enum initializes as null.
+ */
+ public static class MockFallbackBinding extends water.bindings.pojos.ModelParametersSchemaV3 {
+ public DummyEnum dummyField = null;
+ }
}