AOCode Public Changelog


Snapshot Notes

  • Split development-only classes into a new sub-project in devel/. This sub-project is used development only and is never deployed to artifact repositories.
  • Reverted a previous change made on 2020-03-01 that was released in version 4.0.0 on 2020-03-25. Encoding of in-context translation lookup markups is required after all.

    One example is the lookup IDs added inside alt attributes like alt="&lt;##&lt;value&gt;##&gt;". With this bug, this was incorrectly written as alt="<##<value>##>", which fails XML validation.

    This bug is unlikely to affect production systems for two reasons:

    1. Lookup markups are only performed when in-context translations are enabled, which is only when in development mode.
    2. Most production sites are served in SGML mode, where browsers will handle the incorrect HTML formatting. XML mode is used in development specifically for this stricter validation.


Release Notes

  • Moved the com.aoindustries.sql package to the new AO SQL project, with the exception of LocalizedSQLException that stays here with other localized exceptions.
  • ConnectionWrapper moved to new com.aoindustries.sql.wrapper package in the new AO SQL Wrapper project.
  • AOConnectionPool moved to new com.aoindustries.sql.pool package in the new AO SQL Pool project.
  • BackgroundCache now allows all Throwable. This is a source-compatible, but binary-incompatible change. A recompile of dependents will is required.
  • Temporary files are now created with more secure default permissions.
  • Now registering exception types for use with Throwables.newSurrogate(…) that supports creating new instances of throwables in order to have caller stack trace. When wrapped, the original throwable is the cause of the new throwable. When not wrapped, the original throwable is used directly and caller stack trace is lost.

    This is used to maintain exception types and states across thread boundaries, such as when an exception cause is obtained from an ExecutionException.

  • Now using instead of WrappedException.


Release Notes

  • Added support for Web development file types *.less, *.sass, *.scss, *, and *


Release Notes

  • ZeroFile no longer writes blank lines when there are no blocks to read or write.


Release Notes

  • ModifiablePropertiesResourceBundle now writes properties files with keys sorted (base, base + MODIFIED_SUFFIX, base + VALIDATED_SUFFIX). This groups the keys together better, which aids version control diffs.


Release Notes

  • Minimum Java version changed from 1.7 to 1.8.
  • Reduced use of property substitutions in pom.xml. This is to help 3rd-party parsers that fail to perform full Maven-compatible substitutions.
  • Deprecated MimeType: This simple hard-coded list of MIME types is not maintained well. It is strongly recommended to use a different, well-supported API.
  • Made EncodingUtils.toString(Object) (deprecated) consistent with Coercion:
    1. Supporting instances of Writable.
    2. Supporting instances of CharSequence.
    3. Supporting instances of char[].
  • EncodingUtils.encodeHtml(*) (deprecated) now require additional isXhtml flag.
  • Connection pool statistics HTML generation now supports both SGML and XML serializations.
  • New bundle lookup markup types:
  • com.aoindustries.util.logging.* significantly reworked to be compatible with
  • TopologicalSorter now returns a modifiable Set. Previously it returned an unmodifiable List.
  • Updated dependencies.
  • Removed the package:
    1. moved to the AO Lang project. Resolves this split-package with AO Lang.
    2. Removed; please use AccountLockedException instead.
    3. Removed; please use AccountNotFoundException instead.
    4. Removed; please use FailedLoginException instead.
    5. Removed; please use CredentialNotFoundException instead.
    6. Removed; please use LoginException instead.
  • Moved the com.aoindustries.util.persistent package to the new AO Persistence project.
  • Split collection-related utilities into new AO Collections project.


Release Notes

  • Now supporting queries and anchors on EditableResourceBundle.setValueUrl.


Release Notes


Release Notes

  • New abstract class ConnectionWrapper split from PostgresqlConnectionWrapper to be used by other implementations of Connection wrapping.
  • Removed some long-deprecated or otherwise long-unused classes and methods:
    1. com.aoindustries.servlet.http.ServletUtil.getResource(*)
    2. com.aoindustries.servlet.http.ServletUtil.resourceExists(*)
    3. com.aoindustries.sql.SQLUtility.escapeSQL(*)
    4. com.aoindustries.sql.SQLUtility.encodeString(String)
    5. com.aoindustries.sql.SQLUtility.decodeString(String)
    6. com.aoindustries.sql.SQLUtility.negIntIfEmpty(String)
    7. com.aoindustries.sql.SQLUtility.negLongIfEmpty(String)
    8. com.aoindustries.sql.SQLUtility.nullIfEmpty(String)
    9. com.aoindustries.sql.SQLUtility.getDaysFromMillis(long)
    10. com.aoindustries.sql.SQLUtility.getMillisFromDays(long)
    11. com.aoindustries.sql.SQLUtility.roundToDay(long)
    12. com.aoindustries.sql.SQLUtility.printResultSetHTMLTable(ResultSet, Appendable, String, boolean)
    13. com.aoindustries.util.Stack
    14. com.aoindustries.util.StringUtility.buildEmailList(String[])
    15. com.aoindustries.util.StringUtility.buildList(*)
    16. com.aoindustries.util.StringUtility.compareToDDMMYYYY(String, String)
    17. com.aoindustries.util.StringUtility.convertStringDateToTime(String)
    18. com.aoindustries.util.StringUtility.countOccurances(*)
    19. com.aoindustries.util.StringUtility.escapeSQL(String)
    20. com.aoindustries.util.StringUtility.getDateMMDDYYYY(String)
    21. com.aoindustries.util.StringUtility.getDateString(*)
    22. com.aoindustries.util.StringUtility.getDateStringMMDDYYYY(Date)
    23. com.aoindustries.util.StringUtility.getDateStringSecond(*)
    24. com.aoindustries.util.StringUtility.getStringArray(List)
    25. com.aoindustries.util.StringUtility.intern(String)
    26. com.aoindustries.util.StringUtility.isValidDate(String)
    27. com.aoindustries.util.StringUtility.leapYear(int)
    28. com.aoindustries.util.StringUtility.removeChars(*)
    29. com.aoindustries.util.WildcardPatternMatcher.getMatchNone()
    30. com.aoindustries.util.WildcardPatternMatcher.getMatchAll()
    31. com.aoindustries.util.WildcardPatternMatcher.getInstance(String)
    32. com.aoindustries.util.logging.ProcessTimer.ProcessTimer(Logger, Random, String, String, String, String, long, long)
    33. com.aoindustries.util.logging.ProcessTimer.finished()
    34. com.aoindustries.util.persistent.PersistentCollections.charToBuffer(*)
    35. com.aoindustries.util.persistent.PersistentCollections.bufferToChar(*)
    36. com.aoindustries.util.persistent.PersistentCollections.shortToBuffer(*)
    37. com.aoindustries.util.persistent.PersistentCollections.bufferToShort(*)
    38. com.aoindustries.util.persistent.PersistentCollections.intToBuffer(*)
    39. com.aoindustries.util.persistent.PersistentCollections.bufferToInt(*)
    40. com.aoindustries.util.persistent.PersistentCollections.longToBuffer(*)
    41. com.aoindustries.util.persistent.PersistentCollections.bufferToLong(*)
  • Significant, breaking changes to SQLUtility:
    1. Renamed getDate(long) to formatDate(long)
    2. Added formatDate(long, TimeZone) for other time zones
    3. Added formatDate(Long) for nullable integers
    4. Added formatDate(Long, TimeZone) for nullable integers
    5. Added formatDate(Date) for dates
    6. Added formatDate(Date, TimeZone) for dates
    7. Renamed getDate(String) to parseDate(String)
    8. Added parseDate(String, TimeZone) for other time zones
    9. Renamed getDateTime(long) to formatDateTime(long)
    10. Added formatDateTime(long, TimeZone) for other time zones
    11. Added formatDateTime(Long) for nullable integers
    12. Added formatDateTime(Long, TimeZone) for nullable integers
    13. Added formatDateTime(Date) for dates
    14. Added formatDateTime(Date, TimeZone) for dates
    15. Renamed getDateTime(String) to parseDateTime(String)
    16. Added parseDateTime(String, TimeZone) for other time zones
    17. Renamed getTime(long) to formatTime(long)
    18. Added formatTime(long, TimeZone) for other time zones
    19. Added formatTime(Long) for nullable integers
    20. Added formatTime(Long, TimeZone) for nullable integers
    21. Added formatTime(Date) for dates
    22. Added formatTime(Date, TimeZone) for dates
    23. Renamed getDecimal(int) to formatDecimal2(int)
    24. Renamed getDecimal(long) to formatDecimal2(long)
    25. Renamed getPennies(String) to parseDecimal2(String)
    26. Renamed getPenniesLong(String) to parseLongDecimal2(String)
    27. Renamed getMilliDecimal(int) to formatDecimal3(int)
    28. Renamed getMilliDecimal(long) to formatDecimal3(long)
    29. Renamed getMillis(String) to parseDecimal3(String)
    30. Added parseLongDecimal3(String)
  • Renamed Compressed* to Streamable* and moved to new package:
    1. Renamed CompressedDataInputStream to StreamableInput.
    2. Renamed CompressedDataOutputStream to StreamableOutput.
    3. Renamed CompressedReadable to StreamReadable.
    4. Renamed CompressedWritable to StreamWritable.
    5. Moved Streamable to Streamable.
  • New methods to read and write possibly nullable Timestamp in StreamableOutput and StreamableInput.

    These methods use a wire protocol deliberately compatible with Instant in Java 8, however the API remains Timestamp-only since the minimum Java version is still 1.7.

  • Added protocol version to reading in Streamable and CompressedReadable, because a server may be reading objects streamed by older clients. Protocol compatibility can be necessary both directions.
  • New methods to read and write possibly nullable Identifier and SmallIdentifier.
  • FileList now implements Closeable.
  • SQLUtility.printTable(…) improvements:
    1. Created a variant of printTable(…) that accepts Iterable<? extends Object[]> for row data. Deprecated the old variants as they forced the caller to combine all their cell values into big collections or arrays, which is not conducive to displaying large, streamed datasets.
    2. printTable(…) now uses code points to correctly align output with characters outside the Basic Multilingual Plane.
    3. Implemented Unicode-formatted output when in interactive mode.
  • New method FifoFile.flush() that may be used to flush the fifo file. This makes sense here because reads also update the underlying fifo persistence.
  • UrlUtils.encodeUrlPath(String, String) now skips encoding the full set of the characters defined in RFC 3986: Reserved Characters. Previously, only a partial subset of these characters were added as-needed. We have now improved the implementation to match the specification.

    This means "mailto:" links will now maintain the "@" in the email address, instead of it being incorrectly percent-encoded.

  • UrlUtils.encodeUrlPath(String, String) now correctly encodes space as %20 instead of +.
  • UrlUtils.encodeUrlPath(String, String) now determines query string or fragment by first ? or #, accordingly, instead of last.
  • UrlUtils.decodeUrlPath(String, String) now re-encodes characters that decode to reserved characters to avoid ambiguity.
  • Case-insensitive matching of URL schemes. Previously, URL schemes were matched case-sensitive, while the spec is case-insensitive. This has been OK given we only use lower-case schemes within our code and tools, but this is now a correct implementation.
  • PersistentLinkedList now implements Deque instead of Queue.


Release Notes

  • Using ;-split-package:=first of maven-bundle-plugin to avoid bundling the classes in the split packages from AO Lang.

    These split packages are transitional. In the future we will have more fine-grained projects.


Release Notes


Release Notes


Release Notes

  • Fixed bug in ByteCountInputStream that subtracted the -1 returned at end of stream.
  • Moved the following classes to the new AO Lang project:
    19. com.aoindustries.lang.Disposable
    20. com.aoindustries.lang.DisposedException
    21. com.aoindustries.lang.EnumUtils
    22. com.aoindustries.lang.LocalizedIllegalArgumentException
    23. com.aoindustries.lang.NotImplementedException
    24. com.aoindustries.lang.NullArgumentException
    25. com.aoindustries.lang.ObjectUtils
    26. com.aoindustries.lang.ProcessResult
    27. com.aoindustries.lang.RuntimeUtils
    28. com.aoindustries.lang.SysExits
    29. com.aoindustries.lang.reflect.Methods
    30. com.aoindustries.lang.reflect.ReflectionException
    31. com.aoindustries.math.BigFraction
    32. com.aoindustries.math.LongLong
    33. com.aoindustries.math.NullMath
    34. com.aoindustries.math.SafeMath
    35. com.aoindustries.math.Statistics
    36. com.aoindustries.math.UnsignedLong
    37. com.aoindustries.nio.charset.Charsets
    42. com.aoindustries.sql.LocalizedSQLException
    43. com.aoindustries.sql.UnmodifiableTimestamp
    44. com.aoindustries.sql.WrappedSQLException
    45. com.aoindustries.text.MessageFormatFactory
    46. com.aoindustries.text.SmartComparator
    47. com.aoindustries.text.UnmodifiableMessageFormat
    48. com.aoindustries.time.Clock
    49. com.aoindustries.time.Duration
    50. com.aoindustries.time.Instant
    51. com.aoindustries.util.AoArrays
    52. com.aoindustries.util.AoCollections
    53. com.aoindustries.util.AtomicSequence
    54. com.aoindustries.util.BufferManager
    55. com.aoindustries.util.CalendarUtils
    56. com.aoindustries.util.ComparatorUtils
    57. com.aoindustries.util.EnumerationIterator
    58. com.aoindustries.util.ErrorPrinter
    59. com.aoindustries.util.GetOpt
    60. com.aoindustries.util.HashCodeComparator
    61. com.aoindustries.util.IdentityKey
    62. com.aoindustries.util.InternUtils
    63. com.aoindustries.util.Internable
    64. com.aoindustries.util.MinimalList
    65. com.aoindustries.util.MinimalMap
    66. com.aoindustries.util.PropertiesUtils
    67. com.aoindustries.util.Sequence
    68. com.aoindustries.util.SortedProperties
    69. com.aoindustries.util.UnmodifiableCalendar
    70. com.aoindustries.util.UnmodifiableDate
    71. com.aoindustries.util.UnsynchronizedSequence
    72. com.aoindustries.util.WrappedException
    73. com.aoindustries.util.WrappedExceptions
    74. com.aoindustries.util.concurrent.ThreadLocalCallable
    75. com.aoindustries.util.concurrent.ThreadLocalRunnable
    76. com.aoindustries.util.concurrent.ThreadLocalsCallable
    77. com.aoindustries.util.concurrent.ThreadLocalsRunnable
    78. com.aoindustries.util.i18n.ApplicationResourcesAccessor
    79. com.aoindustries.util.i18n.CurrencyComparator
    80. com.aoindustries.util.i18n.LocaleComparator
    81. com.aoindustries.util.i18n.LocaleString
    82. com.aoindustries.util.i18n.Locales
    83. com.aoindustries.util.i18n.Money
    84. com.aoindustries.util.i18n.ThreadLocale
    88. com.aoindustries.xml.XmlUtils
  • New interfaces CompressedReadable and CompressedWritable for code that only needs to handle one direction of Streamable.
  • AOPool improvements:
    1. More fine-grained locking through atomics.
    2. No longer holding connection lock while connecting.
    3. Non-blocking statistics methods.
    4. Bug fix: Notifying other threads on connection allocation.
  • CompressedDataOutputStream and CompressedDataInputStream now support streaming of Enums.
  • Updated dependencies.
  • WildcardPatternMatcher improvements:
    1. Coalesces adjacent '*' into a single '*' during parsing.
    2. Compiles patterns instead of interpreting them on the fly.
    3. Supports any arbitrary patterns containing '*'.
    4. Fast-path checks for none, all, prefix, suffix, and exact matches.
    5. Renamed methods to better represent the functionality. Left deprecated methods for compatibility.
    6. Added test suite to verify correctness and benchmark versus equivalent regular expressions.
      1. The typical performance is 8 to 10 times that of the regular expressions.
      2. Some operations, in particular suffix matching on long strings, can be as high as 2000 times the performance of regular expressions. This is not so uncommon, a typical use-case for wildcard patterns is "*.jpg".
    7. Like any typical "contains" or "indexOf" string operation, the infix matching can fall-flat when trying to find long strings of repeating patterns within an almost-as-long string of repeating patterns following by non-matching padding. When strictly using prefix or suffix matching this will never occur.


Release Notes

  • New AO OSS Parent POM to simplify pom.xml files.
  • Project documentation moved to per-project book in SemanticCMS format.
  • Added changelog as top-level project link.
  • Added utility to find the maximum non-null value.
  • Added support for XML DOM Node in toString type coercion.


Release Notes


Release Notes

  • Main method to generate a random Identifier.
  • Improved Javadoc formatting.
  • Improved README formatting.
  • Allowing varargs for locales.


Release Notes

  • Moved servlet-specific methods to a different class to avoid introducing compile-time dependencies on servlet api to non-servlet projects.


Release Notes


  • Java 1.7 compatible long sorting for pre-Java 1.7 use.
  • Now automatically maintains some ThreadLocal values between caller and executor during concurrent processing, and provides wrapper hook for subclasses to extend.
  • Recurring now allows null during parsing and returns null.
  • Convenience method to make unmodifiable from MinimalList and MinimalMap.
  • Background-refreshed cache implementation.
  • Caching access to ServletContext to improve performance.


  • Improved Javadoc formatting.
  • Additional compiler flags in preparation to do away with our old Ant build system.
  • Using request object instead of ThreadLocals to support asynchronous and concurrent request processing.
  • Working on thread safety for concurrent sub requests.
  • Avoiding setting ThreadLocal when value has not changed.
  • nullIfEmpty moved to StringUtility.
  • Each lock object now a small empty class to help identify lock contention.

    The lock contention profiler in NetBeans is just showing "java.lang.Object" all over, and can't seem to get from the lock object id to the actual object in the heap dump using OQL (id not found).

  • Using minimal list to efficiently filter small numbers of matches.
  • Number of buffers is now unlimited.


Release Notes

  • Improved Maven configuration for Java EE 6 dependencies.


Release Notes

  • Efficient way to check if writables empty.


Release Notes

  • Wildcard to show immutability just cluttered the API, reverted.


Release Notes

  • Allowing ao-taglib style "arg" maps to be passed through Dispatcher for non-taglib use.
  • args passed unmodifiable.
  • Passing args as Map<String,?> instead of forcing Map<String,Object>
  • Returning wildcard bound list as it better captures the essence of the unmodifiable list returned.
  • Java 1.7 compatible boolean sorting for pre-Java 1.7 use.


Release Notes

  • Reverted to Java 1.6 for Android and Java EE 6 compatibility.


Release Notes

  • Testing if nexus-staging:release required when using autoReleaseAfterClose=true
  • Now deployed to The Central Repository.


Release Notes

  • Java EE 6 optional, since only used by a subset of the features.
  • Preparing to deploy to The Central Repository.


Release Notes

  • Project moved to GitHub and Maven.
  • Ignoring locales with scripts or extensions since this API predates them.