Skip to content
Open
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
168 changes: 168 additions & 0 deletions openml-xgboost/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2026 Feedzai
~
~ Licensed 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
~
~ http://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.
~
-->

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.feedzai</groupId>
<artifactId>openml-java</artifactId>
<version>0.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>openml-xgboost</artifactId>
<name>OpenML XGBoost</name>
<description>Provider that imports, scores and trains XGBoost models using the native xgboost4j JVM package.</description>

<properties>
<!--
xgboost4j is the pure-JVM core of XGBoost. The published jar bundles the native library for
linux/x86_64, linux/aarch64, macos/x86_64, macos/aarch64 and windows/x86_64, so it works on
ARM (AWS Graviton / Apple Silicon) out of the box - unlike H2O-XGBoost (AMD64 only).
It is a thin JNI wrapper (no H2O-style JDK version gate), so it runs on Java 8-25.
-->
<xgboost.version>3.4.0</xgboost.version>
</properties>

<dependencies>
<dependency>
<groupId>com.feedzai</groupId>
<artifactId>openml-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.feedzai</groupId>
<artifactId>openml-utils</artifactId>
<scope>provided</scope>
</dependency>

<!--
xgboost4j core (Java API: ml.dmlc.xgboost4j.java.{XGBoost,Booster,DMatrix}).
The artifact carries a Scala suffix; we use the _2.12 build to match Pulse's Scala 2.12
classpath, even though this provider only uses the pure-Java API. scala-compiler is not
needed at all, so it is excluded to keep the classpath lean.

kryo is excluded because xgboost4j (via its parent pom) pulls Kryo 5, whose
com.esotericsoftware.kryo.Kryo would clash on the class path with the Kryo 4 (kryo-shaded)
that Pulse and Spark rely on (Kryo 5 removed the nested Kryo.DefaultInstantiatorStrategy).
xgboost4j's Booster implements com.esotericsoftware.kryo.KryoSerializable, so kryo classes
must still be present at runtime - Pulse supplies them via kryo-shaded 4. To keep this module
self-contained for its own build/tests, kryo is re-declared below in 'provided' scope, which
is NOT propagated transitively to consumers.
-->
<dependency>
<groupId>ml.dmlc</groupId>
<artifactId>xgboost4j_2.12</artifactId>
<version>${xgboost.version}</version>
<exclusions>
<exclusion>
<groupId>org.scala-lang</groupId>
<artifactId>scala-compiler</artifactId>
</exclusion>
<exclusion>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--
Needed only so xgboost4j's Booster (implements KryoSerializable) can load during this module's
own compilation and tests. 'provided' scope keeps it off consumers' transitive class paths so
it never clashes with the host's Kryo (e.g. Pulse's kryo-shaded 4).

INVARIANT (why the Kryo-5-at-compile / Kryo-4-at-runtime mismatch is safe): a loaded Booster is
never Kryo-serialized in the Pulse runtime. Models are not shipped as serialized objects across
Spark boundaries - Pulse's DistributedModelLoader uses BundleZipModelLoadingStrategy, which zips
the model folder and rebuilds the model on the remote side via the provider's loadModel (reading
the .ubj file from disk). No Kryo registrator registers Booster or ClassificationMLModel, so
Booster.write/read(Kryo, ...) is never invoked. Therefore the Kryo 5 API that Booster is compiled
against is never exercised against Pulse's Kryo 4 instance. If this invariant ever changes (e.g.
a Spark path that broadcasts/caches a Booster-backed model via a Kryo serializer), this provided
strategy must be revisited and covered by an integration test on a Kryo-4 classpath.
-->
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>5.6.2</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service</artifactId>
</dependency>

<!--Testing-->
<dependency>
<groupId>com.feedzai</groupId>
<artifactId>openml-utils</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<!-- allow to reuse the objects created in test directory from outside of this module -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright 2026 Feedzai
*
* Licensed 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
*
* http://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 com.feedzai.openml.provider.xgboost;

import com.feedzai.openml.provider.descriptor.MLAlgorithmDescriptor;
import com.feedzai.openml.provider.descriptor.MachineLearningAlgorithmType;
import com.feedzai.openml.util.algorithm.MLAlgorithmEnum;

import static com.feedzai.openml.util.algorithm.MLAlgorithmEnum.createDescriptor;

/**
* Specifies the XGBoost algorithms that can be imported and trained through this provider.
*/
public enum XgboostAlgorithms implements MLAlgorithmEnum {

/**
* XGBoost binary classifier.
*/
XGBOOST_BINARY_CLASSIFIER(createDescriptor(
"DMLC - XGBoost",
XgboostDescriptorUtil.PARAMS,
MachineLearningAlgorithmType.SUPERVISED_BINARY_CLASSIFICATION,
Comment thread
gandola marked this conversation as resolved.
"https://xgboost.readthedocs.io/"
));

/**
* {@link MLAlgorithmDescriptor} for this algorithm.
*/
private final MLAlgorithmDescriptor descriptor;

/**
* Constructor.
*
* @param descriptor {@link MLAlgorithmDescriptor} for this algorithm.
*/
XgboostAlgorithms(final MLAlgorithmDescriptor descriptor) {
this.descriptor = descriptor;
}

@Override
public MLAlgorithmDescriptor getAlgorithmDescriptor() {
return this.descriptor;
}
}
Loading
Loading