-
Notifications
You must be signed in to change notification settings - Fork 532
/
CirceSupportParser.scala
154 lines (137 loc) · 5.74 KB
/
CirceSupportParser.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
* Copyright 2023 circe
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.circe.jawn
import io.circe.Json
import io.circe.JsonNumber
import io.circe.JsonObject
import org.typelevel.jawn.FContext
import org.typelevel.jawn.Facade
import org.typelevel.jawn.SupportParser
import java.io.Serializable
import java.util.LinkedHashMap
object CirceSupportParser extends CirceSupportParser(None, true)
class CirceSupportParser(maxValueSize: Option[Int], allowDuplicateKeys: Boolean)
extends SupportParser[Json]
with Serializable {
implicit final val facade: Facade[Json] = maxValueSize match {
case Some(size) =>
if (allowDuplicateKeys) {
new LimitedFacade(size) with DuplicatesFacade
} else {
new LimitedFacade(size) with NoDuplicatesFacade
}
case None =>
if (allowDuplicateKeys) {
new UnlimitedFacade with DuplicatesFacade
} else {
new UnlimitedFacade with NoDuplicatesFacade
}
}
private[this] abstract class BaseFacade extends Facade[Json] with Serializable {
final def jnull(index: Int): Json = Json.Null
final def jfalse(index: Int): Json = Json.False
final def jtrue(index: Int): Json = Json.True
final def singleContext(index: Int): FContext[Json] = new FContext[Json] {
private[this] final var value: Json = null
final def add(s: CharSequence, index: Int): Unit = value = jstring(s.toString, index)
final def add(v: Json, index: Int): Unit = value = v
final def finish(index: Int): Json = value
final def isObj: Boolean = false
}
final def arrayContext(index: Int): FContext[Json] = new FContext[Json] {
private[this] final val vs = Vector.newBuilder[Json]
final def add(s: CharSequence, index: Int): Unit = vs += jstring(s.toString, index)
final def add(v: Json, index: Int): Unit = vs += v
final def finish(index: Int): Json = Json.fromValues(vs.result())
final def isObj: Boolean = false
}
protected[this] def mapPut(map: LinkedHashMap[String, Json], key: String, value: Json): Unit
}
private[this] abstract class LimitedFacade(maxValueSize: Int) extends BaseFacade {
final def jnum(s: CharSequence, decIndex: Int, expIndex: Int, index: Int): Json =
if (s.length > maxValueSize) {
throw new IllegalArgumentException(s"JSON number length (${s.length}) exceeds limit ($maxValueSize)")
} else {
if (decIndex < 0 && expIndex < 0) {
Json.fromJsonNumber(JsonNumber.fromIntegralStringUnsafe(s.toString))
} else {
Json.fromJsonNumber(JsonNumber.fromDecimalStringUnsafe(s.toString))
}
}
final def jstring(s: CharSequence, index: Int): Json = if (s.length > maxValueSize) {
throw new IllegalArgumentException(s"JSON string length (${s.length}) exceeds limit ($maxValueSize)")
} else {
Json.fromString(s.toString)
}
final def objectContext(index: Int): FContext[Json] = new FContext[Json] {
private[this] final var key: String = null
private[this] final val m = new LinkedHashMap[String, Json]
final def add(s: CharSequence, index: Int): Unit =
if (key.eq(null)) {
if (s.length > maxValueSize) {
throw new IllegalArgumentException(s"JSON key length (${s.length}) exceeds limit ($maxValueSize)")
} else {
key = s.toString
}
} else {
mapPut(m, key, jstring(s, index))
key = null
}
final def add(v: Json, index: Int): Unit = {
mapPut(m, key, v)
key = null
}
final def finish(index: Int): Json = Json.fromJsonObject(JsonObject.fromLinkedHashMap(m))
final def isObj: Boolean = true
}
}
private[this] abstract class UnlimitedFacade extends BaseFacade {
final def jnum(s: CharSequence, decIndex: Int, expIndex: Int, index: Int): Json =
if (decIndex < 0 && expIndex < 0) {
Json.fromJsonNumber(JsonNumber.fromIntegralStringUnsafe(s.toString))
} else {
Json.fromJsonNumber(JsonNumber.fromDecimalStringUnsafe(s.toString))
}
final def jstring(s: CharSequence, index: Int): Json = Json.fromString(s.toString)
final def objectContext(index: Int): FContext[Json] = new FContext[Json] {
private[this] final var key: String = null
private[this] final val m = new LinkedHashMap[String, Json]
final def add(s: CharSequence, index: Int): Unit =
if (key.eq(null)) {
key = s.toString
} else {
mapPut(m, key, jstring(s, index))
key = null
}
final def add(v: Json, index: Int): Unit = {
mapPut(m, key, v)
key = null
}
final def finish(index: Int): Json = Json.fromJsonObject(JsonObject.fromLinkedHashMap(m))
final def isObj: Boolean = true
}
}
private[this] trait DuplicatesFacade extends BaseFacade {
protected[this] final def mapPut(map: LinkedHashMap[String, Json], key: String, value: Json): Unit =
map.put(key, value)
}
private[this] trait NoDuplicatesFacade extends BaseFacade {
protected[this] final def mapPut(map: LinkedHashMap[String, Json], key: String, value: Json): Unit =
if (map.put(key, value).ne(null)) {
throw new IllegalArgumentException(s"Invalid json, duplicate key name found: $key")
}
}
}