Skip to content

Non-deterministic HashMap iteration affects build cache reliability #42

Description

@Besi97

Problem

MappingConfig uses HashMap and HashSet extensively. When these collections are iterated during code generation, the order can vary between JVM runs due to hash randomization.

This causes non-deterministic output when multiple regex patterns in customAnnotationsMapping match the same type.

Example

Given this configuration:

customAnnotationsMapping = {
  ".*TO$" -> ["@Auditable"],      // matches "ProductTO"
  "Product.*" -> ["@Cached"]      // also matches "ProductTO"
}

When generating ProductTO, both regex patterns match. Depending on HashMap iteration order:

Run 1: .*TO$ first, then Product.*

@Auditable
@Cached
public class ProductTO { ... }

Run 2: Product.* first, then .*TO$

@Cached
@Auditable
public class ProductTO { ... }

The annotations are semantically identical, but byte-for-byte different.

Impact on Build Caching

Cache hits: Work correctly — Gradle retrieves the exact cached output regardless of HashMap ordering.

Cache misses: Can produce different outputs on each run, making the cache unreliable when:

  • Cache is frequently cleared
  • Multiple developers share a cache
  • Byte-for-byte reproducibility is required

Options to Fix

Option 1: Sort during iteration

Sort map entries by key during code generation:

map.entrySet().stream()
    .sorted(Map.Entry.comparingByKey())
    .forEach(entry -> { ... });

Option 2: Use sorted collections

Replace HashMap/HashSet with TreeMap/TreeSet in MappingConfig:

private Map<String, List<String>> customAnnotationsMapping = new TreeMap<>();

Option 3: Sort before code generation

Collect items into sorted lists before generating code.

Affected Code

  • src/main/java/io/github/besi97/graphql/codegen/mapper/AnnotationsMapper.java:153 — iterates customAnnotationsMapping.entrySet()
  • src/main/java/io/github/besi97/graphql/codegen/model/MappingConfig.java — uses HashMap and HashSet for configuration properties
  • Additional iteration points throughout the codebase (25 occurrences found)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions