Hi everyone,
Wanted to give everyone a heads up about a change in Lucee 7.1 that’s already caught out a couple of major projects.
We are close to our first RC for 7.1
What changed
In 7.1, we replaced Lucee’s internal ConcurrentHashMap implementation with a modern wrapper around Java’s java.util.concurrent.ConcurrentHashMap (LDEV-5908). This is a significant performance win — up to 2.7x faster under high contention — but it changes the iteration order of keys in regular (unordered) structs.
Regular structs have never guaranteed key ordering in CFML. But in practice, the old implementation happened to produce a consistent order, and a lot of code ended up depending on that accident.
What breaks
If your code does any of the following with regular structs, it may produce different results in 7.1:
- Comparing
serializeJSON()output as strings (e.g. in tests or caching) - Generating hashes or cache keys from serialized structs
- Building strings by iterating struct keys and expecting a stable order
- MockBox
$args()matching on nested struct arguments
We’ve already seen real-world breakage in:
- PresideCMS — 11 test failures across multiple suites, plus a production concern where FK constraint names are derived from serialized struct output, potentially triggering unnecessary DB migrations on upgrade (PRESIDECMS-3264)
- TestBox/MockBox —
$args()matcher fails when nested structs have different insertion order, becausenormalizeArguments()falls through tostruct.toString()for nested values (TESTBOX-448)
What to do
- Use ordered structs where key order matters:
structNew("ordered")or[:]notation - Compare deserialized structs instead of raw JSON strings
- Sort keys when generating deterministic output (cache keys, hashes, markup)
- Review your test suites — if tests pass on 7.0 but fail on 7.1, struct ordering assumptions are the most likely culprit
Full details in the breaking changes doc:
If you hit anything related that isn’t covered above, please let us know.