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
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ CI checks enforce those conventions too, so be sure to build your project with M
./mvnw clean install
```

For information about how to set up code style checks in your IDE, see [IDE Setup Instructions](https://github.com/TimefoldAI/timefold-solver/blob/main/build/ide-config/ide-configuration.adoc).
For information about how to set up code style checks in your IDE, see [IDE Setup Instructions](build/ide-config/ide-configuration.adoc).

**Key code style conventions** (see [Constitution](.specify/memory/constitution.md) for complete details):
- Automatic formatting via Maven build
Expand Down
17 changes: 0 additions & 17 deletions build/bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,23 +48,6 @@
<type>test-jar</type>
<version>${version.ai.timefold.solver}</version>
</dependency>
<dependency>
<groupId>ai.timefold.solver</groupId>
<artifactId>timefold-solver-persistence-common</artifactId>
<version>${version.ai.timefold.solver}</version>
</dependency>
<dependency>
<groupId>ai.timefold.solver</groupId>
<artifactId>timefold-solver-persistence-common</artifactId>
<version>${version.ai.timefold.solver}</version>
<classifier>sources</classifier>
</dependency>
<dependency>
<groupId>ai.timefold.solver</groupId>
<artifactId>timefold-solver-persistence-common</artifactId>
<type>test-jar</type>
<version>${version.ai.timefold.solver}</version>
</dependency>
<dependency>
<groupId>ai.timefold.solver</groupId>
<artifactId>timefold-solver-jaxb</artifactId>
Expand Down
40 changes: 27 additions & 13 deletions build/build-parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<version.org.apache.logging.log4j>2.25.3</version.org.apache.logging.log4j>
<version.org.assertj>3.27.7</version.org.assertj>
<version.org.awaitility>4.3.0</version.org.awaitility>
<version.org.eclipse.microprofile.config>3.1.1-RC1</version.org.eclipse.microprofile.config>
<version.org.freemarker>2.3.34</version.org.freemarker>
<version.org.jfree.jfreechart>1.5.6</version.org.jfree.jfreechart>
<version.org.jspecify>1.0.0</version.org.jspecify>
Expand Down Expand Up @@ -60,9 +61,6 @@
<!-- Plugin configuration properties -->
<maven.min.version>3.9.11</maven.min.version> <!-- The same as the version in .mvn/maven-wrapper.properties -->
<maven.compiler.release>21</maven.compiler.release>
<!-- This property needs to be defined in all modules that use the packaging 'jar'.
It is used by different plugins to make sure the module/bundle names are consistent. -->
<java.module.name/>
<spotless.skip>false</spotless.skip>
<spotless.goal>apply</spotless.goal>
<!-- JaCoCo coverage data file location -->
Expand Down Expand Up @@ -369,16 +367,6 @@
<artifactId>maven-jar-plugin</artifactId>
<version>${version.jar.plugin}</version>
<executions>
<execution>
<id>default-jar</id>
<configuration>
<archive>
<manifestEntries combine.children="append">
<Automatic-Module-Name>${java.module.name}</Automatic-Module-Name>
</manifestEntries>
</archive>
</configuration>
</execution>
<execution>
<id>test-jar</id>
<goals>
Expand Down Expand Up @@ -454,6 +442,28 @@
<compilerArgument>-Xlint:none</compilerArgument>
</compilerArgs>
</configuration>
<executions>
<execution>
<id>default-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<!-- no useModulePath override here -->
</execution>

<!-- test compile: force classpath (no module-path) -->
<execution>
<id>default-testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
<configuration>
<useModulePath>false</useModulePath>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
Expand Down Expand Up @@ -568,13 +578,17 @@
<artifactId>maven-surefire-plugin</artifactId>
<version>${version.surefire.plugin}</version>
<configuration>
<!-- Currently not running on the module path, despite including JPMS -->
<useModulePath>false</useModulePath>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${version.surefire.plugin}</version>
<configuration>
<!-- Currently not running on the module path, despite including JPMS -->
<useModulePath>false</useModulePath>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
</configuration>
<executions>
Expand Down
18 changes: 14 additions & 4 deletions build/ide-config/ide-configuration.adoc
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
= IDE code style setup
= Configuring your IDE for Timefold Solver

== Running tests in your IDE

Timefold Solver is https://en.wikipedia.org/wiki/Java_Platform_Module_System[a modular project].
However, its test coverage runs on the classpath, not the module path.
Maven respects this and runs the tests on the classpath, but IDEs don't always do that by default.
If you're running your tests in the IDE and seeing errors about missing modules,
you need to configure your IDE to run the tests on the classpath.

== IDE code style setup

Every Maven build formats the source code with the standard code style.
This avoids merge conflicts and code style discussions.

Configure it in your favorite IDE too:

== IDEA setup
=== IDEA setup

. Open the _Settings_ window (or _Preferences_ depending on your edition) and navigate to _Plugins_.

Expand All @@ -26,7 +36,7 @@ file in the `build/ide-config/src/main/resources/` directory.

. Open the _Editor -> Code Style -> Java -> Imports_ settings and set the _Class count to use import with '\*'_ to 999. This is to avoid the `*` imports, which should only be used in special cases.

== Eclipse setup
=== Eclipse setup

. Open the _Preferences_ window, and then navigate to _Java -> Code Style -> Formatter_.

Expand All @@ -36,7 +46,7 @@ file in the `build/ide-config/src/main/resources/` directory.

. Click Import and select the `build/ide-config/src/main/resources/eclipse.importorder` file.

== VS Code setup
=== VS Code setup

. Open the _Extensions_ window (Ctrl+Shift+X) and search for _Language Support for Java(TM)_ and install it.

Expand Down
4 changes: 0 additions & 4 deletions build/ide-config/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,4 @@
</description>
<url>https://solver.timefold.ai</url>

<properties>
<java.module.name>ai.timefold.solver.ide.config</java.module.name>
</properties>

</project>
4 changes: 0 additions & 4 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@
</description>
<url>https://solver.timefold.ai</url>

<properties>
<java.module.name>ai.timefold.solver.core</java.module.name>
</properties>

<dependencies>

<!-- Gizmo dependencies -->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package ai.timefold.solver.persistence.common.api.domain.solution;
package ai.timefold.solver.core.api.domain.solution;

import java.io.File;

import ai.timefold.solver.core.api.domain.solution.PlanningSolution;

/**
* Reads or writes a {@link PlanningSolution} from or to a {@link File}.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import ai.timefold.solver.core.config.heuristic.selector.move.MoveSelectorConfig;
import ai.timefold.solver.core.config.util.ConfigUtils;
import ai.timefold.solver.core.impl.heuristic.selector.move.factory.MoveIteratorFactory;
import ai.timefold.solver.core.impl.io.jaxb.adapter.JaxbCustomPropertiesAdapter;
import ai.timefold.solver.core.impl.io.jaxb.JaxbCustomPropertiesAdapter;

import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
Expand All @@ -25,7 +25,7 @@ public class MoveIteratorFactoryConfig extends MoveSelectorConfig<MoveIteratorFa
protected Class<? extends MoveIteratorFactory> moveIteratorFactoryClass = null;

@XmlJavaTypeAdapter(JaxbCustomPropertiesAdapter.class)
protected Map<String, String> moveIteratorFactoryCustomProperties = null;
protected @Nullable Map<String, String> moveIteratorFactoryCustomProperties = null;

public @Nullable Class<? extends MoveIteratorFactory> getMoveIteratorFactoryClass() {
return moveIteratorFactoryClass;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import ai.timefold.solver.core.config.heuristic.selector.move.MoveSelectorConfig;
import ai.timefold.solver.core.config.util.ConfigUtils;
import ai.timefold.solver.core.impl.heuristic.selector.move.factory.MoveListFactory;
import ai.timefold.solver.core.impl.io.jaxb.adapter.JaxbCustomPropertiesAdapter;
import ai.timefold.solver.core.impl.io.jaxb.JaxbCustomPropertiesAdapter;

import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import ai.timefold.solver.core.config.phase.PhaseConfig;
import ai.timefold.solver.core.config.phase.custom.CustomPhaseConfig;
import ai.timefold.solver.core.config.util.ConfigUtils;
import ai.timefold.solver.core.impl.io.jaxb.adapter.JaxbCustomPropertiesAdapter;
import ai.timefold.solver.core.impl.io.jaxb.JaxbCustomPropertiesAdapter;
import ai.timefold.solver.core.impl.partitionedsearch.partitioner.SolutionPartitioner;

import org.jspecify.annotations.NonNull;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import ai.timefold.solver.core.api.solver.phase.PhaseCommand;
import ai.timefold.solver.core.config.phase.PhaseConfig;
import ai.timefold.solver.core.config.util.ConfigUtils;
import ai.timefold.solver.core.impl.io.jaxb.adapter.JaxbCustomPropertiesAdapter;
import ai.timefold.solver.core.impl.io.jaxb.JaxbCustomPropertiesAdapter;

import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import ai.timefold.solver.core.api.score.stream.ConstraintProvider;
import ai.timefold.solver.core.config.AbstractConfig;
import ai.timefold.solver.core.config.util.ConfigUtils;
import ai.timefold.solver.core.impl.io.jaxb.adapter.JaxbCustomPropertiesAdapter;
import ai.timefold.solver.core.impl.io.jaxb.JaxbCustomPropertiesAdapter;

import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import ai.timefold.solver.core.config.AbstractConfig;
import ai.timefold.solver.core.config.util.ConfigUtils;
import ai.timefold.solver.core.impl.io.jaxb.adapter.JaxbDurationAdapter;
import ai.timefold.solver.core.impl.io.jaxb.JaxbDurationAdapter;

import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import ai.timefold.solver.core.config.AbstractConfig;
import ai.timefold.solver.core.config.util.ConfigUtils;
import ai.timefold.solver.core.impl.io.jaxb.adapter.JaxbDurationAdapter;
import ai.timefold.solver.core.impl.io.jaxb.JaxbDurationAdapter;

import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
import org.xml.sax.SAXNotSupportedException;

@NullMarked
public final class GenericJaxbIO<T> implements JaxbIO<T> {
public final class GenericJaxbIO<T> {

public static DocumentBuilderFactory createDocumentBuilderFactory() {
try {
Expand Down Expand Up @@ -122,7 +122,6 @@ public GenericJaxbIO(Class<T> rootClass, int indentation) {
}
}

@Override
public T read(Reader reader) {
try {
return (T) createUnmarshaller().unmarshal(reader);
Expand Down Expand Up @@ -265,7 +264,6 @@ public void validate(Document document, Schema schema) {
}
}

@Override
public void write(T root, Writer writer) {
write(root, writer, null);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package ai.timefold.solver.core.impl.io.jaxb;

import java.util.List;

import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlType;

import ai.timefold.solver.core.config.solver.SolverConfig;

import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

// Required to generate the XSD type in the same namespace.
@NullMarked
@XmlType(namespace = SolverConfig.XML_NAMESPACE)
public final class JaxbAdaptedMap {

@XmlElement(name = "property", namespace = SolverConfig.XML_NAMESPACE)
private @Nullable List<JaxbAdaptedMapEntry> entries;

public JaxbAdaptedMap() {
// Required by JAXB
}

public JaxbAdaptedMap(@Nullable List<JaxbAdaptedMapEntry> entries) {
this.entries = entries;
}

public @Nullable List<JaxbAdaptedMapEntry> getEntries() {
return entries;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package ai.timefold.solver.core.impl.io.jaxb;

import jakarta.xml.bind.annotation.XmlAttribute;
import jakarta.xml.bind.annotation.XmlType;

import ai.timefold.solver.core.config.solver.SolverConfig;

import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

// Required to generate the XSD type in the same namespace.
@NullMarked
@XmlType(namespace = SolverConfig.XML_NAMESPACE)
public final class JaxbAdaptedMapEntry {

@XmlAttribute
private @Nullable String name;

@XmlAttribute
private @Nullable String value;

public JaxbAdaptedMapEntry() {
}

public JaxbAdaptedMapEntry(@Nullable String name, @Nullable String value) {
this.name = name;
this.value = value;
}

public @Nullable String getName() {
return name;
}

public @Nullable String getValue() {
return value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package ai.timefold.solver.core.impl.io.jaxb;

import java.util.Collections;
import java.util.Map;
import java.util.stream.Collectors;

import jakarta.xml.bind.annotation.adapters.XmlAdapter;

import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

@NullMarked
public class JaxbCustomPropertiesAdapter extends XmlAdapter<JaxbAdaptedMap, Map<String, String>> {

@Override
public @Nullable Map<String, String> unmarshal(@Nullable JaxbAdaptedMap jaxbAdaptedMap) {
if (jaxbAdaptedMap == null) {
return null;
}
var entries = jaxbAdaptedMap.getEntries();
if (entries == null || entries.isEmpty()) {
return Collections.emptyMap();
}
return entries.stream()
.collect(Collectors.toMap(JaxbAdaptedMapEntry::getName, JaxbAdaptedMapEntry::getValue));
}

@Override
public @Nullable JaxbAdaptedMap marshal(@Nullable Map<String, String> originalMap) {
if (originalMap == null) {
return null;
}
var entries = originalMap.entrySet().stream()
.map(entry -> new JaxbAdaptedMapEntry(entry.getKey(), entry.getValue()))
.toList();
return new JaxbAdaptedMap(entries);
}

}
Loading
Loading