Details
-
Type:
Defect
-
Status:
Closed
-
Priority:
Minor
-
Resolution: Declined
-
Affects Version/s: None
-
Fix Version/s: Release 1.7
-
Component/s: None
-
Labels:
-
Patch:Code and Test
-
Approval:Incomplete
Description
The reader tries to read a record instead of a literal if the tag contains periods.
user> (binding [*data-readers* {'foo/bar #'identity}] (read-string "#foo/bar 1")) 1 user> (binding [*data-readers* {'foo/bar.x #'identity}] (read-string "#foo/bar.x 1")) ClassNotFoundException foo/bar.x java.lang.Class.forName0 (Class.java:-2)
Summary of reader forms:
Kind | Example | Constraint | Status |
Record | #user.Foo[1] | record class name | OK |
Class | #java.lang.String["abc"] | class name | OK |
Clojure reader tag | #uuid "c48d7d6e-f3bb-425a-abc5-44bd014a511d" | not a class name, no "/" | OK |
Library reader tag | #my/card "5H" | not a class name, has "/" | OK |
#my.ns/card "5H" | not a class name, has "/" | OK | |
#my/playing.card "5H" | not a class name, has "/" | BROKEN - read as record |
Note: reader tags should not be allowed to override the record reader.
Cause: In LispReader, CtorReader.invoke() decides between record and tagged literal based on whether the tag has a ".".
Proposed: Change the discriminator in CtorReader by doing more string inspection:
- If name has a "/" -> readTagged (not a legal class name)
- If name has no "/" or "." -> readTagged (records must have qualified names)
- Else -> readRecord (also covers Java classes)
Tradeoffs: Clojure-defined data reader tags must not contain periods. Not possible to read a Java class with no package. Avoids unnecessary class loading/construction for all tags.
Patch: CLJ-1100-v2.patch
Screened by: Alex Miller
Alternatives considered:
Using class checks:
- Attempt readRecord (also covers Java classes)
- If failed, attempt readTagged
Tradeoffs: Clojure tags could not override Java/record constructors - not sure that's something we'd ever want to do, but this would cut that off. This alternative may attempt classloading when it would not have before.
The suggested patch (clj-1100-reader-literal-periods.patch) will break reading records when *default-data-reader-fn* is set. Try adding a test like this: