Skip to content
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
77 changes: 77 additions & 0 deletions spawn-jdk/src/main/java/build/spawn/jdk/Architecture.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package build.spawn.jdk;

/*-
* #%L
* Spawn JDK
* %%
* Copyright (C) 2026 Workday, Inc.
* %%
* 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.
* #L%
*/

import java.util.Locale;

/**
* The CPU architecture a {@link JDK} was built for.
*
* @author reed.vonredwitz
* @since Jul-2026
*/
public enum Architecture {

/**
* 64-bit x86 (aka {@code amd64}, {@code x86_64}).
*/
X86_64,

/**
* 64-bit ARM (aka {@code aarch64}, {@code arm64}).
*/
AARCH64,

/**
* An architecture that could not be recognized.
*/
OTHER;

/**
* Determines the {@link Architecture} for the specified name, typically sourced from the
* {@code OS_ARCH} entry of a JDK's {@code release} file or the {@code os.arch} system property.
*
* @param name the architecture name
* @return the {@link Architecture}, or {@link #OTHER} if it can't be recognized
*/
public static Architecture of(final String name) {
final var lower = name.toLowerCase(Locale.ROOT);

if (lower.equals("amd64") || lower.equals("x86_64")) {
return X86_64;
}
if (lower.equals("aarch64") || lower.equals("arm64")) {
return AARCH64;
}

return OTHER;
}

/**
* Obtains the {@link Architecture} of the currently executing Virtual Machine, based on the
* {@code os.arch} system property.
*
* @return the current {@link Architecture}
*/
public static Architecture current() {
return of(System.getProperty("os.arch", ""));
}
}
69 changes: 60 additions & 9 deletions spawn-jdk/src/main/java/build/spawn/jdk/JDK.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,30 @@ public final class JDK
*/
private final JDKHome home;

/**
* The {@link OperatingSystem} the {@link JDK} was built for.
*/
private final OperatingSystem operatingSystem;

/**
* The {@link Architecture} the {@link JDK} was built for.
*/
private final Architecture architecture;

/**
* Constructs a {@link JDK}.
*
* @param version the {@link JDKVersion}
* @param home the {@link JDKHome}
* @param version the {@link JDKVersion}
* @param home the {@link JDKHome}
* @param operatingSystem the {@link OperatingSystem} the {@link JDK} was built for
* @param architecture the {@link Architecture} the {@link JDK} was built for
*/
private JDK(final JDKVersion version, final JDKHome home) {
private JDK(final JDKVersion version, final JDKHome home, final OperatingSystem operatingSystem,
final Architecture architecture) {
this.version = Objects.requireNonNull(version, "The JDKVersion must not be null");
this.home = Objects.requireNonNull(home, "The JDKHome must not be null");
this.operatingSystem = Objects.requireNonNull(operatingSystem, "The OperatingSystem must not be null");
this.architecture = Objects.requireNonNull(architecture, "The Architecture must not be null");
}

/**
Expand All @@ -73,9 +88,28 @@ public JDKHome home() {
return this.home;
}

/**
* Obtains the {@link OperatingSystem} the {@link JDK} was built for.
*
* @return the {@link OperatingSystem}
*/
public OperatingSystem operatingSystem() {
return this.operatingSystem;
}

/**
* Obtains the {@link Architecture} the {@link JDK} was built for.
*
* @return the {@link Architecture}
*/
public Architecture architecture() {
return this.architecture;
}

@Override
public String toString() {
return "JDK{version=" + this.version + ", home=" + this.home.path() + "}";
return "JDK{version=" + this.version + ", home=" + this.home.path()
+ ", os=" + this.operatingSystem + ", arch=" + this.architecture + "}";
}

@Override
Expand All @@ -91,12 +125,13 @@ public boolean equals(final Object object) {
if (!(object instanceof final JDK other)) {
return false;
}
return Objects.equals(this.version, other.version) && Objects.equals(this.home, other.home);
return Objects.equals(this.version, other.version) && Objects.equals(this.home, other.home)
&& this.operatingSystem == other.operatingSystem && this.architecture == other.architecture;
}

@Override
public int hashCode() {
return Objects.hash(this.version, this.home);
return Objects.hash(this.version, this.home, this.operatingSystem, this.architecture);
}

/**
Expand All @@ -109,17 +144,33 @@ public int hashCode() {
* @return the current {@link JDK}
*/
public static JDK current() {
return of(JDKVersion.current(), JDKHome.current());
return of(JDKVersion.current(), JDKHome.current(), OperatingSystem.current(), Architecture.current());
}

/**
* Creates a {@link JDK} based on the specified {@link JDKVersion} and {@link JDKHome}.
* Creates a {@link JDK} based on the specified {@link JDKVersion} and {@link JDKHome}, assuming it was
* built for the {@link OperatingSystem} and {@link Architecture} of the currently executing Virtual Machine.
*
* @param version the {@link JDKVersion}
* @param home the {@link JDKHome}
* @return a new {@link JDK}
*/
public static JDK of(final JDKVersion version, final JDKHome home) {
return new JDK(version, home);
return of(version, home, OperatingSystem.current(), Architecture.current());
}

/**
* Creates a {@link JDK} based on the specified {@link JDKVersion}, {@link JDKHome}, {@link OperatingSystem}
* and {@link Architecture}.
*
* @param version the {@link JDKVersion}
* @param home the {@link JDKHome}
* @param operatingSystem the {@link OperatingSystem} the {@link JDK} was built for
* @param architecture the {@link Architecture} the {@link JDK} was built for
* @return a new {@link JDK}
*/
public static JDK of(final JDKVersion version, final JDKHome home, final OperatingSystem operatingSystem,
final Architecture architecture) {
return new JDK(version, home, operatingSystem, architecture);
}
}
85 changes: 85 additions & 0 deletions spawn-jdk/src/main/java/build/spawn/jdk/OperatingSystem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package build.spawn.jdk;

/*-
* #%L
* Spawn JDK
* %%
* Copyright (C) 2026 Workday, Inc.
* %%
* 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.
* #L%
*/

import java.util.Locale;

/**
* The operating system a {@link JDK} was built for.
*
* @author reed.vonredwitz
* @since Jul-2026
*/
public enum OperatingSystem {

/**
* Linux.
*/
LINUX,

/**
* macOS.
*/
MAC,

/**
* Windows.
*/
WINDOWS,

/**
* An operating system that could not be recognized.
*/
OTHER;

/**
* Determines the {@link OperatingSystem} for the specified name, typically sourced from the
* {@code OS_NAME} entry of a JDK's {@code release} file or the {@code os.name} system property.
*
* @param name the operating system name
* @return the {@link OperatingSystem}, or {@link #OTHER} if it can't be recognized
*/
public static OperatingSystem of(final String name) {
final var lower = name.toLowerCase(Locale.ROOT);

if (lower.contains("mac") || lower.contains("darwin")) {
return MAC;
}
if (lower.contains("windows")) {
return WINDOWS;
}
if (lower.contains("linux")) {
return LINUX;
}

return OTHER;
}

/**
* Obtains the {@link OperatingSystem} of the currently executing Virtual Machine, based on the
* {@code os.name} system property.
*
* @return the current {@link OperatingSystem}
*/
public static OperatingSystem current() {
return of(System.getProperty("os.name", ""));
}
}
57 changes: 57 additions & 0 deletions spawn-jdk/src/test/java/build/spawn/jdk/ArchitectureTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package build.spawn.jdk;

import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Tests for {@link Architecture}.
*
* @author reed.vonredwitz
* @since Jul-2026
*/
class ArchitectureTests {

/**
* Ensure the common x86-64 spellings are recognized.
*/
@Test
void shouldRecognizeX86_64() {
assertThat(Architecture.of("amd64")).isEqualTo(Architecture.X86_64);
assertThat(Architecture.of("x86_64")).isEqualTo(Architecture.X86_64);
}

/**
* Ensure the common AArch64 spellings are recognized.
*/
@Test
void shouldRecognizeAarch64() {
assertThat(Architecture.of("aarch64")).isEqualTo(Architecture.AARCH64);
assertThat(Architecture.of("arm64")).isEqualTo(Architecture.AARCH64);
}

/**
* Ensure an unrecognized architecture name falls back to {@link Architecture#OTHER}.
*/
@Test
void shouldFallBackToOtherForUnrecognizedName() {
assertThat(Architecture.of("riscv64")).isEqualTo(Architecture.OTHER);
}

/**
* Ensure matching is case-insensitive.
*/
@Test
void shouldMatchCaseInsensitively() {
assertThat(Architecture.of("AMD64")).isEqualTo(Architecture.X86_64);
}

/**
* Ensure {@link Architecture#current()} matches the {@code os.arch} system property.
*/
@Test
void currentShouldMatchOsArchSystemProperty() {
assertThat(Architecture.current())
.isEqualTo(Architecture.of(System.getProperty("os.arch", "")));
}
}
Loading
Loading