Repository navigation
Description
Usage sharing is being aligned across every language to the record the .NET packages write, which draft specifications#65 describes byte for byte. The Java record, read at 40b615c, differs from it in these ways.
- Document. There is no byte order mark and no XML declaration, because
writeStartDocumentis never called, and the root is<Devices version="1.1">where the specification has<Devices>(ShareUsageElement.java#L407-L409). - Element order.
Version,Product,FlowElement,Language,LanguageVersion,ServerIPandPlatformcome first, thenSessionId,Sequence,DateSentandClientIP. The specification starts with those last four (ShareUsageElement.java#L424-L451). SessionIdandClientIPare left out when the Evidence has no value for them, and an element whose content is empty is written<SessionId></SessionId>. The specification always writes both, and writes an empty one as<SessionId />(ShareUsageElement.java#L476-L485).DateSentcomes from aSimpleDateFormatwith no time zone set, so it is the JVM's local time rather than UTC (ShareUsageBase.java#L63-L64, ShareUsageElement.java#L449).ServerIPis the local address of a UDP socket connected to8.8.8.8, which is the address the machine would use to reach the internet, rather than the first suitable address the host name resolves to (ShareUsageBase.java#L491-L506).FlowElementholds the bare class name fromgetSimpleName()rather than the fully qualified name (ShareUsageBase.java#L464).Platformisos.namealone, such asLinux, with no operating system version (ShareUsageBase.java#L419).- The three special keys are matched with case, so a key such as
Query.Session-Idis treated as an ordinary query parameter andSessionIdis left out (ShareUsageBase.java#L708-L727). - Entries are grouped in hash maps, so prefixes and entries come out in hash order. The Evidence is also held sorted without regard to case, so the order it was given in is lost before grouping starts (ShareUsageBase.java#L810-L829, EvidenceDefault.java#L42).
- Values are written as escaped element text, never CDATA (ShareUsageElement.java#L469).
- Truncation cuts at 512 UTF-16 code units and marks the entry
truncated="true", where the specification cuts at 10,000 behind the[TRUNCATED BY USAGE SHARING]prefix (Constants.java#L34, ShareUsageElement.java#L466-L468, ShareUsageElement.java#L518-L521). - Character replacement turns every character outside U+0020 to U+007E and U+00A0 to U+00FF into U+FFFD, tab, line feed, carriage return and U+007F to U+009F included, and marks the entry
replaced="true". Names are not checked. The specification replaces only characters from U+0000 to U+001F other than tab, line feed and carriage return, writes each as\xand four lowercase hex digits, and adds<BadSchema>true</BadSchema>(ShareUsageElement.java#L490-L502, ShareUsageElement.java#L522-L529, ShareUsageElement.java#L457-L465). - The XML writer comes from
XMLOutputFactory.newInstance(), which picks up any other XML writer library on the application's classpath, so how empty elements and escapes are written depends on the application (ShareUsageElement.java#L332). - Request detail. The content type is
text/xml; charset=utf-8rather thantext/xml, and a failure logs only the status code, because the response content is never read (ShareUsageElement.java#L328, ShareUsageElement.java#L395-L398).
Also found, outside the record writer:
- The filter shares a query parameter only when it is in the allow list, so the specification's example entry
query.51D_Testis not shared by default, where the specification also shares every query parameter starting51D_(EvidenceKeyFilterShareUsage.java#L134-L138).
What to change
Write the record exactly as the Processing section in specifications#65 describes, so the same Evidence gives the same bytes as the .NET packages, apart from DateSent and the values that name the runtime. Keeping the order the Evidence was given in changes the core Evidence type, which sorts its keys, not only this element, and the record needs an XML writer whose output does not depend on the classpath.
The pull request goes into the rc branch, not main, because changes are collected there and released together.
Done when
A test writes a document from fixed Evidence, the specification's example among it, and compares it byte for byte with the expected text. The cases include the byte order mark and declaration, an absent session id and client IP (<SessionId /> and <ClientIP />), a value of more than 10,000 UTF-16 code units, a control character, a value containing ]]>, keys whose order must be kept, a key with no ., and DateSent in UTC when the JVM's default time zone is not UTC.
The same change for the Rust crates is 51Degrees/51degrees-rust#232.
Activity
jwrosewell commentedon Nov 9, 2026
The record to write is the one in the Processing section of usage-sharing-element.md on
rc, not the one this issue first pointed to. That draft, specifications#65, is closed and was not adopted.So a replaced character marks its element
escaped="true", a shortened value marks ittruncated="true", and there is no CDATA and no BadSchema. .NET keeps its current record for now, as reference-implementation-notes.md records, and moves to the specification's record later.Write the usage sharing record as the specification's Processing sect…