SOLR-4607: use noggit 0.5 release jar

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1457811 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Robert Muir 2013-03-18 15:28:35 +00:00
parent a4d66b3e1d
commit edc777e22e
38 changed files with 255 additions and 1976 deletions

View File

@ -197,6 +197,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.noggit</groupId>
<artifactId>noggit</artifactId>
<version>0.5</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>

View File

@ -85,6 +85,10 @@
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>org.noggit</groupId>
<artifactId>noggit</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>

View File

@ -183,6 +183,8 @@ Other Changes
* SOLR-4544: Refactor HttpShardHandlerFactory so load-balancing logic can be customized.
(Ryan Ernst via Robert Muir)
* SOLR-4607: Use noggit 0.5 release jar rather than a forked copy. (Yonik Seeley, Robert Muir)
================== 4.2.1 ==================
Versions of Major Components

View File

@ -22,8 +22,8 @@ import java.io.StringReader;
import java.util.*;
import org.apache.commons.io.IOUtils;
import org.apache.noggit.JSONParser;
import org.apache.noggit.ObjectBuilder;
import org.noggit.JSONParser;
import org.noggit.ObjectBuilder;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.SolrInputField;

View File

@ -23,9 +23,9 @@ import org.apache.lucene.util.Attribute;
import org.apache.lucene.util.AttributeSource;
import org.apache.lucene.util.AttributeSource.State;
import org.apache.lucene.util.BytesRef;
import org.apache.noggit.JSONUtil;
import org.apache.noggit.JSONWriter;
import org.apache.noggit.ObjectBuilder;
import org.noggit.JSONUtil;
import org.noggit.JSONWriter;
import org.noggit.ObjectBuilder;
import org.apache.solr.common.util.Base64;
import org.apache.solr.schema.PreAnalyzedField.ParseResult;
import org.apache.solr.schema.PreAnalyzedField.PreAnalyzedParser;

View File

@ -24,7 +24,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apache.noggit.JSONParser;
import org.noggit.JSONParser;
import org.apache.lucene.analysis.util.ResourceLoader;
import org.apache.lucene.util.IOUtils;
import org.apache.solr.common.SolrException;

View File

@ -32,8 +32,8 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.IOUtils;
import org.apache.noggit.CharArr;
import org.apache.noggit.JSONWriter;
import org.noggit.CharArr;
import org.noggit.JSONWriter;
import org.apache.solr.cloud.ZkController;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.cloud.SolrZkClient;

View File

@ -18,8 +18,8 @@
package org.apache.solr;
import org.apache.lucene.search.FieldCache;
import org.apache.noggit.JSONUtil;
import org.apache.noggit.ObjectBuilder;
import org.noggit.JSONUtil;
import org.noggit.ObjectBuilder;
import org.apache.solr.client.solrj.impl.BinaryResponseParser;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.GroupParams;

View File

@ -21,8 +21,8 @@ import org.apache.lucene.search.FieldCache;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.BooleanQuery;
import org.apache.noggit.JSONUtil;
import org.apache.noggit.ObjectBuilder;
import org.noggit.JSONUtil;
import org.noggit.ObjectBuilder;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.core.SolrCore;
import org.apache.solr.handler.JsonUpdateRequestHandler;

View File

@ -17,7 +17,7 @@
package org.apache.solr.request;
import org.apache.noggit.ObjectBuilder;
import org.noggit.ObjectBuilder;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.ModifiableSolrParams;

View File

@ -18,7 +18,7 @@ package org.apache.solr.search;
import org.apache.lucene.util.LuceneTestCase.Slow;
import org.apache.noggit.ObjectBuilder;
import org.noggit.ObjectBuilder;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.request.SolrQueryRequest;

View File

@ -17,7 +17,7 @@
package org.apache.solr.search;
import org.apache.noggit.ObjectBuilder;
import org.noggit.ObjectBuilder;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.update.DirectUpdateHandler2;

View File

@ -18,7 +18,7 @@ package org.apache.solr.search;
import org.apache.lucene.util.Constants;
import org.apache.noggit.ObjectBuilder;
import org.noggit.ObjectBuilder;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.update.UpdateHandler;
import org.apache.solr.update.UpdateLog;

View File

@ -17,7 +17,7 @@
package org.apache.solr.search;
import org.apache.noggit.ObjectBuilder;
import org.noggit.ObjectBuilder;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.util.TestHarness;
import org.junit.BeforeClass;

View File

@ -17,7 +17,7 @@
package org.apache.solr.search;
import org.apache.noggit.ObjectBuilder;
import org.noggit.ObjectBuilder;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.util.TestHarness;
import org.junit.BeforeClass;

View File

@ -18,7 +18,7 @@ package org.apache.solr.update.processor;
*/
import com.google.common.collect.Maps;
import org.apache.noggit.ObjectBuilder;
import org.noggit.ObjectBuilder;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.common.SolrInputDocument;

View File

@ -0,0 +1 @@
8e6e65624d2e09a30190c6434abe23b7d4e5413c

View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View File

@ -0,0 +1,3 @@
noggit
https://github.com/yonik/noggit

View File

@ -44,6 +44,7 @@
<dependency org="org.codehaus.woodstox" name="wstx-asl" rev="3.2.7" transitive="false"/>
<dependency org="org.slf4j" name="slf4j-api" rev="1.6.4" transitive="false"/>
<dependency org="org.slf4j" name="slf4j-jdk14" rev="1.6.4" transitive="false"/>
<dependency org="org.noggit" name="noggit" rev="0.5" transitive="false"/>
<exclude org="*" ext="*" matcher="regexp" type="${ivy.exclude.types}"/>
</dependencies>
</ivy-module>

View File

@ -1,372 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.noggit;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.nio.CharBuffer;
// CharArr origins
// V1.0 7/06/97
// V1.1 9/21/99
// V1.2 2/02/04 // Java5 features
// V1.3 11/26/06 // Make safe for Java 1.4, work into Noggit
// Java5 version could look like the following:
// public class CharArr implements CharSequence, Appendable, Readable, Closeable {
/**
*/
public class CharArr implements CharSequence, Appendable {
protected char[] buf;
protected int start;
protected int end;
public CharArr() {
this(32);
}
public CharArr(int size) {
buf = new char[size];
}
public CharArr(char[] arr, int start, int end) {
set(arr,start,end);
}
public void setStart(int start) { this.start = start; }
public void setEnd(int end) { this.end = end; }
public void set(char[] arr, int start, int end) {
this.buf = arr;
this.start = start;
this.end = end;
}
public char[] getArray() { return buf; }
public int getStart() { return start; }
public int getEnd() { return end; }
public int size() { return end-start; }
@Override
public int length() { return size(); }
public int capacity() { return buf.length; }
@Override
public char charAt(int index) {
return buf[start+index];
}
@Override
public CharArr subSequence(int start, int end) {
return new CharArr(buf, this.start+start, this.start+end);
}
public int read() throws IOException {
if (start>=end) return -1;
return buf[start++];
}
public int read(char cbuf[], int off, int len) {
//TODO
return 0;
}
public void unsafeWrite(char b) {
buf[end++] = b;
}
public void unsafeWrite(int b) { unsafeWrite((char)b); }
public void unsafeWrite(char b[], int off, int len) {
System.arraycopy(b, off, buf, end, len);
end += len;
}
protected void resize(int len) {
char newbuf[] = new char[Math.max(buf.length << 1, len)];
System.arraycopy(buf, start, newbuf, 0, size());
buf = newbuf;
}
public void reserve(int num) {
if (end + num > buf.length) resize(end + num);
}
public void write(char b) {
if (end >= buf.length) {
resize(end+1);
}
unsafeWrite(b);
}
public final void write(int b) { write((char)b); }
public final void write(char[] b) {
write(b,0,b.length);
}
public void write(char b[], int off, int len) {
reserve(len);
unsafeWrite(b, off, len);
}
public final void write(CharArr arr) {
write(arr.buf, start, end-start);
}
public final void write(String s) {
write(s, 0, s.length());
}
public void write(String s, int stringOffset, int len) {
reserve(len);
s.getChars(stringOffset, len, buf, end);
end += len;
}
public void flush() {
}
public final void reset() {
start = end = 0;
}
public void close() {
}
public char[] toCharArray() {
char newbuf[] = new char[size()];
System.arraycopy(buf, start, newbuf, 0, size());
return newbuf;
}
@Override
public String toString() {
return new String(buf, start, size());
}
public int read(CharBuffer cb) throws IOException {
/***
int sz = size();
if (sz<=0) return -1;
if (sz>0) cb.put(buf, start, sz);
return -1;
***/
int sz = size();
if (sz>0) cb.put(buf, start, sz);
start=end;
while (true) {
fill();
int s = size();
if (s==0) return sz==0 ? -1 : sz;
sz += s;
cb.put(buf, start, s);
}
}
public int fill() throws IOException {
return 0; // or -1?
}
//////////////// Appendable methods /////////////
@Override
public final Appendable append(CharSequence csq) throws IOException {
return append(csq, 0, csq.length());
}
@Override
public Appendable append(CharSequence csq, int start, int end) throws IOException {
write(csq.subSequence(start, end).toString());
return null;
}
@Override
public final Appendable append(char c) {
write(c);
return this;
}
}
class NullCharArr extends CharArr {
public NullCharArr() {
super(new char[1],0,0);
}
@Override
public void unsafeWrite(char b) {}
@Override
public void unsafeWrite(char b[], int off, int len) {}
@Override
public void unsafeWrite(int b) {}
@Override
public void write(char b) {}
@Override
public void write(char b[], int off, int len) {}
@Override
public void reserve(int num) {}
@Override
protected void resize(int len) {}
@Override
public Appendable append(CharSequence csq, int start, int end) throws IOException {
return this;
}
@Override
public char charAt(int index) {
return 0;
}
@Override
public void write(String s, int stringOffset, int len) {
}
}
// IDEA: a subclass that refills the array from a reader?
class CharArrReader extends CharArr {
protected final Reader in;
public CharArrReader(Reader in, int size) {
super(size);
this.in = in;
}
@Override
public int read() throws IOException {
if (start>=end) fill();
return start>=end ? -1 : buf[start++];
}
@Override
public int read(CharBuffer cb) throws IOException {
// empty the buffer and then read direct
int sz = size();
if (sz>0) cb.put(buf,start,end);
int sz2 = in.read(cb);
if (sz2>=0) return sz+sz2;
return sz>0 ? sz : -1;
}
@Override
public int fill() throws IOException {
if (start>=end) {
reset();
} else if (start>0) {
System.arraycopy(buf, start, buf, 0, size());
end=size(); start=0;
}
/***
// fill fully or not???
do {
int sz = in.read(buf,end,buf.length-end);
if (sz==-1) return;
end+=sz;
} while (end < buf.length);
***/
int sz = in.read(buf,end,buf.length-end);
if (sz>0) end+=sz;
return sz;
}
}
class CharArrWriter extends CharArr {
protected Writer sink;
@Override
public void flush() {
try {
sink.write(buf, start, end-start);
} catch (IOException e) {
throw new RuntimeException(e);
}
start = end = 0;
}
@Override
public void write(char b) {
if (end >= buf.length) {
flush();
}
unsafeWrite(b);
}
@Override
public void write(char b[], int off, int len) {
int space = buf.length - end;
if (len < space) {
unsafeWrite(b, off, len);
} else if (len < buf.length) {
unsafeWrite(b, off, space);
flush();
unsafeWrite(b, off+space, len-space);
} else {
flush();
try {
sink.write(b, off, len);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void write(String s, int stringOffset, int len) {
int space = buf.length - end;
if (len < space) {
s.getChars(stringOffset, stringOffset+len, buf, end);
end += len;
} else if (len < buf.length) {
// if the data to write is small enough, buffer it.
s.getChars(stringOffset, stringOffset+space, buf, end);
flush();
s.getChars(stringOffset+space, stringOffset+len, buf, 0);
end = len-space;
} else {
flush();
// don't buffer, just write to sink
try {
sink.write(s, stringOffset, len);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}

View File

@ -1,53 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.noggit;
/**
*/
public class CharUtil {
// belongs in number utils or charutil?
public long parseLong(char[] arr, int start, int end) {
long x = 0;
boolean negative = arr[start] == '-';
for (int i=negative ? start+1 : start; i<end; i++) {
// If constructing the largest negative number, this will overflow
// to the largest negative number. This is OK since the negation of
// the largest negative number is itself in two's complement.
x = x * 10 + (arr[i] - '0');
}
// could replace conditional-move with multiplication of sign... not sure
// which is faster.
return negative ? -x : x;
}
public int compare(char[] a, int a_start, int a_end, char[] b, int b_start, int b_end) {
int a_len = a_end - a_start;
int b_len = b_end - b_start;
int len = Math.min(a_len,b_len);
while (--len>=0) {
int c = a[a_start] - b[b_start];
if (c!=0) return c;
a_start++; b_start++;
}
return a_len-b_len;
}
}

View File

@ -1,837 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.noggit;
import java.io.IOException;
import java.io.Reader;
/**
*/
public class JSONParser {
/** Event indicating a JSON string value, including member names of objects */
public static final int STRING=1;
/** Event indicating a JSON number value which fits into a signed 64 bit integer */
public static final int LONG=2;
/** Event indicating a JSON number value which has a fractional part or an exponent
* and with string length <= 23 chars not including sign. This covers
* all representations of normal values for Double.toString().
*/
public static final int NUMBER=3;
/** Event indicating a JSON number value that was not produced by toString of any
* Java primitive numerics such as Double or Long. It is either
* an integer outside the range of a 64 bit signed integer, or a floating
* point value with a string representation of more than 23 chars.
*/
public static final int BIGNUMBER=4;
/** Event indicating a JSON boolean */
public static final int BOOLEAN=5;
/** Event indicating a JSON null */
public static final int NULL=6;
/** Event indicating the start of a JSON object */
public static final int OBJECT_START=7;
/** Event indicating the end of a JSON object */
public static final int OBJECT_END=8;
/** Event indicating the start of a JSON array */
public static final int ARRAY_START=9;
/** Event indicating the end of a JSON array */
public static final int ARRAY_END=10;
/** Event indicating the end of input has been reached */
public static final int EOF=11;
public static class ParseException extends RuntimeException {
public ParseException(String msg) {
super(msg);
}
}
public static String getEventString( int e )
{
switch( e )
{
case STRING: return "STRING";
case LONG: return "LONG";
case NUMBER: return "NUMBER";
case BIGNUMBER: return "BIGNUMBER";
case BOOLEAN: return "BOOLEAN";
case NULL: return "NULL";
case OBJECT_START: return "OBJECT_START";
case OBJECT_END: return "OBJECT_END";
case ARRAY_START: return "ARRAY_START";
case ARRAY_END: return "ARRAY_END";
case EOF: return "EOF";
}
return "Unknown: "+e;
}
private static final CharArr devNull = new NullCharArr();
final char[] buf; // input buffer with JSON text in it
int start; // current position in the buffer
int end; // end position in the buffer (one past last valid index)
final Reader in; // optional reader to obtain data from
boolean eof=false; // true if the end of the stream was reached.
long gpos; // global position = gpos + start
int event; // last event read
public JSONParser(Reader in) {
this(in, new char[8192]);
// 8192 matches the default buffer size of a BufferedReader so double
// buffering of the data is avoided.
}
public JSONParser(Reader in, char[] buffer) {
this.in = in;
this.buf = buffer;
}
// idea - if someone passes us a CharArrayReader, we could
// directly use that buffer as it's protected.
public JSONParser(char[] data, int start, int end) {
this.in = null;
this.buf = data;
this.start = start;
this.end = end;
}
public JSONParser(String data) {
this(data, 0, data.length());
}
public JSONParser(String data, int start, int end) {
this.in = null;
this.start = start;
this.end = end;
this.buf = new char[end-start];
data.getChars(start,end,buf,0);
}
// temporary output buffer
private final CharArr out = new CharArr(64);
// We need to keep some state in order to (at a minimum) know if
// we should skip ',' or ':'.
private byte[] stack = new byte[16];
private int ptr=0; // pointer into the stack of parser states
private byte state=0; // current parser state
// parser states stored in the stack
private static final byte DID_OBJSTART =1; // '{' just read
private static final byte DID_ARRSTART =2; // '[' just read
private static final byte DID_ARRELEM =3; // array element just read
private static final byte DID_MEMNAME =4; // object member name (map key) just read
private static final byte DID_MEMVAL =5; // object member value (map val) just read
// info about value that was just read (or is in the middle of being read)
private int valstate;
// push current parser state (use at start of new container)
private final void push() {
if (ptr >= stack.length) {
// doubling here is probably overkill, but anything that needs to double more than
// once (32 levels deep) is very atypical anyway.
byte[] newstack = new byte[stack.length<<1];
System.arraycopy(stack,0,newstack,0,stack.length);
stack = newstack;
}
stack[ptr++] = state;
}
// pop parser state (use at end of container)
private final void pop() {
if (--ptr<0) {
throw err("Unbalanced container");
} else {
state = stack[ptr];
}
}
protected void fill() throws IOException {
if (in!=null) {
gpos += end;
start=0;
int num = in.read(buf,0,buf.length);
end = num>=0 ? num : 0;
}
if (start>=end) eof=true;
}
private void getMore() throws IOException {
fill();
if (start>=end) {
throw err(null);
}
}
protected int getChar() throws IOException {
if (start>=end) {
fill();
if (start>=end) return -1;
}
return buf[start++];
}
private int getCharNWS() throws IOException {
for (;;) {
int ch = getChar();
if (!(ch==' ' || ch=='\t' || ch=='\n' || ch=='\r')) return ch;
}
}
private void expect(char[] arr) throws IOException {
for (int i=1; i<arr.length; i++) {
int ch = getChar();
if (ch != arr[i]) {
throw err("Expected " + new String(arr));
}
}
}
private ParseException err(String msg) {
// We can't tell if EOF was hit by comparing start<=end
// because the illegal char could have been the last in the buffer
// or in the stream. To deal with this, the "eof" var was introduced
if (!eof && start>0) start--; // backup one char
String chs = "char=" + ((start>=end) ? "(EOF)" : "" + (char)buf[start]);
String pos = "position=" + (gpos+start);
String tot = chs + ',' + pos + getContext();
if (msg==null) {
if (start>=end) msg = "Unexpected EOF";
else msg="JSON Parse Error";
}
return new ParseException(msg + ": " + tot);
}
private String getContext() {
String context = "";
if (start>=0) {
context += " BEFORE='" + errEscape(Math.max(start-60,0), start+1) + "'";
}
if (start<end) {
context += " AFTER='" + errEscape(start+1, start+40) + "'";
}
return context;
}
private String errEscape(int a, int b) {
b = Math.min(b, end);
if (a>=b) return "";
return new String(buf, a, b-a).replaceAll("\\s+"," ");
}
private boolean bool; // boolean value read
private long lval; // long value read
private int nstate; // current state while reading a number
private static final int HAS_FRACTION = 0x01; // nstate flag, '.' already read
private static final int HAS_EXPONENT = 0x02; // nstate flag, '[eE][+-]?[0-9]' already read
/** Returns the long read... only significant if valstate==LONG after
* this call. firstChar should be the first numeric digit read.
*/
private long readNumber(int firstChar, boolean isNeg) throws IOException {
out.unsafeWrite(firstChar); // unsafe OK since we know output is big enough
// We build up the number in the negative plane since it's larger (by one) than
// the positive plane.
long v = '0' - firstChar;
// can't overflow a long in 18 decimal digits (i.e. 17 additional after the first).
// we also need 22 additional to handle double so we'll handle in 2 separate loops.
int i;
for (i=0; i<17; i++) {
int ch = getChar();
// TODO: is this switch faster as an if-then-else?
switch(ch) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
v = v*10 - (ch-'0');
out.unsafeWrite(ch);
continue;
case '.':
out.unsafeWrite('.');
valstate = readFrac(out,22-i);
return 0;
case 'e':
case 'E':
out.unsafeWrite(ch);
nstate=0;
valstate = readExp(out,22-i);
return 0;
default:
// return the number, relying on nextEvent() to return an error
// for invalid chars following the number.
if (ch!=-1) --start; // push back last char if not EOF
valstate = LONG;
return isNeg ? v : -v;
}
}
// after this, we could overflow a long and need to do extra checking
boolean overflow = false;
long maxval = isNeg ? Long.MIN_VALUE : -Long.MAX_VALUE;
for (; i<22; i++) {
int ch = getChar();
switch(ch) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (v < (0x8000000000000000L/10)) overflow=true; // can't multiply by 10 w/o overflowing
v *= 10;
int digit = ch - '0';
if (v < maxval + digit) overflow=true; // can't add digit w/o overflowing
v -= digit;
out.unsafeWrite(ch);
continue;
case '.':
out.unsafeWrite('.');
valstate = readFrac(out,22-i);
return 0;
case 'e':
case 'E':
out.unsafeWrite(ch);
nstate=0;
valstate = readExp(out,22-i);
return 0;
default:
// return the number, relying on nextEvent() to return an error
// for invalid chars following the number.
if (ch!=-1) --start; // push back last char if not EOF
valstate = overflow ? BIGNUMBER : LONG;
return isNeg ? v : -v;
}
}
nstate=0;
valstate = BIGNUMBER;
return 0;
}
// read digits right of decimal point
private int readFrac(CharArr arr, int lim) throws IOException {
nstate = HAS_FRACTION; // deliberate set instead of '|'
while(--lim>=0) {
int ch = getChar();
if (ch>='0' && ch<='9') {
arr.write(ch);
} else if (ch=='e' || ch=='E') {
arr.write(ch);
return readExp(arr,lim);
} else {
if (ch!=-1) start--; // back up
return NUMBER;
}
}
return BIGNUMBER;
}
// call after 'e' or 'E' has been seen to read the rest of the exponent
private int readExp(CharArr arr, int lim) throws IOException {
nstate |= HAS_EXPONENT;
int ch = getChar(); lim--;
if (ch=='+' || ch=='-') {
arr.write(ch);
ch = getChar(); lim--;
}
// make sure at least one digit is read.
if (ch<'0' || ch>'9') {
throw err("missing exponent number");
}
arr.write(ch);
return readExpDigits(arr,lim);
}
// continuation of readExpStart
private int readExpDigits(CharArr arr, int lim) throws IOException {
while (--lim>=0) {
int ch = getChar();
if (ch>='0' && ch<='9') {
arr.write(ch);
} else {
if (ch!=-1) start--; // back up
return NUMBER;
}
}
return BIGNUMBER;
}
private void continueNumber(CharArr arr) throws IOException {
if (arr != out) arr.write(out);
if ((nstate & HAS_EXPONENT)!=0){
readExpDigits(arr, Integer.MAX_VALUE);
return;
}
if (nstate != 0) {
readFrac(arr, Integer.MAX_VALUE);
return;
}
for(;;) {
int ch = getChar();
if (ch>='0' && ch <='9') {
arr.write(ch);
} else if (ch=='.') {
arr.write(ch);
readFrac(arr,Integer.MAX_VALUE);
return;
} else if (ch=='e' || ch=='E') {
arr.write(ch);
readExp(arr,Integer.MAX_VALUE);
return;
} else {
if (ch!=-1) start--;
return;
}
}
}
private int hexval(int hexdig) {
if (hexdig>='0' && hexdig <='9') {
return hexdig-'0';
} else if (hexdig>='A' && hexdig <='F') {
return hexdig+(10-'A');
} else if (hexdig>='a' && hexdig <='f') {
return hexdig+(10-'a');
}
throw err("invalid hex digit");
}
// backslash has already been read when this is called
private char readEscapedChar() throws IOException {
switch (getChar()) {
case '"' : return '"';
case '\\' : return '\\';
case '/' : return '/';
case 'n' : return '\n';
case 'r' : return '\r';
case 't' : return '\t';
case 'f' : return '\f';
case 'b' : return '\b';
case 'u' :
return (char)(
(hexval(getChar()) << 12)
| (hexval(getChar()) << 8)
| (hexval(getChar()) << 4)
| (hexval(getChar())));
}
throw err("Invalid character escape in string");
}
// a dummy buffer we can use to point at other buffers
private final CharArr tmp = new CharArr(null,0,0);
private CharArr readStringChars() throws IOException {
char c=0;
int i;
for (i=start; i<end; i++) {
c = buf[i];
if (c=='"') {
tmp.set(buf,start,i); // directly use input buffer
start=i+1; // advance past last '"'
return tmp;
} else if (c=='\\') {
break;
}
}
out.reset();
readStringChars2(out, i);
return out;
}
// middle is the pointer to the middle of a buffer to start scanning for a non-string
// character ('"' or "/"). start<=middle<end
// this should be faster for strings with fewer escapes, but probably slower for many escapes.
private void readStringChars2(CharArr arr, int middle) throws IOException {
for (;;) {
if (middle>=end) {
arr.write(buf,start,middle-start);
start=middle;
getMore();
middle=start;
}
int ch = buf[middle++];
if (ch=='"') {
int len = middle-start-1;
if (len>0) arr.write(buf,start,len);
start=middle;
return;
} else if (ch=='\\') {
int len = middle-start-1;
if (len>0) arr.write(buf,start,len);
start=middle;
arr.write(readEscapedChar());
middle=start;
}
}
}
/*** alternate implelentation
// middle is the pointer to the middle of a buffer to start scanning for a non-string
// character ('"' or "/"). start<=middle<end
private void readStringChars2a(CharArr arr, int middle) throws IOException {
int ch=0;
for(;;) {
// find the next non-string char
for (; middle<end; middle++) {
ch = buf[middle];
if (ch=='"' || ch=='\\') break;
}
arr.write(buf,start,middle-start);
if (middle>=end) {
getMore();
middle=start;
} else {
start = middle+1; // set buffer pointer to correct spot
if (ch=='"') {
valstate=0;
return;
} else if (ch=='\\') {
arr.write(readEscapedChar());
if (start>=end) getMore();
middle=start;
}
}
}
}
***/
// return the next event when parser is in a neutral state (no
// map separators or array element separators to read
private int next(int ch) throws IOException {
for(;;) {
switch (ch) {
case ' ':
case '\t': break;
case '\r':
case '\n': break; // try and keep track of linecounts?
case '"' :
valstate = STRING;
return STRING;
case '{' :
push();
state= DID_OBJSTART;
return OBJECT_START;
case '[':
push();
state=DID_ARRSTART;
return ARRAY_START;
case '0' :
out.reset();
//special case '0'? If next char isn't '.' val=0
ch=getChar();
if (ch=='.') {
start--; ch='0';
readNumber('0',false);
return valstate;
} else if (ch>'9' || ch<'0') {
out.unsafeWrite('0');
if (ch!=-1) start--;
lval = 0;
valstate=LONG;
return LONG;
} else {
throw err("Leading zeros not allowed");
}
case '1' :
case '2' :
case '3' :
case '4' :
case '5' :
case '6' :
case '7' :
case '8' :
case '9' :
out.reset();
lval = readNumber(ch,false);
return valstate;
case '-' :
out.reset();
out.unsafeWrite('-');
ch = getChar();
if (ch<'0' || ch>'9') throw err("expected digit after '-'");
lval = readNumber(ch,true);
return valstate;
case 't':
valstate=BOOLEAN;
// TODO: test performance of this non-branching inline version.
// if ((('r'-getChar())|('u'-getChar())|('e'-getChar())) != 0) err("");
expect(JSONUtil.TRUE_CHARS);
bool=true;
return BOOLEAN;
case 'f':
valstate=BOOLEAN;
expect(JSONUtil.FALSE_CHARS);
bool=false;
return BOOLEAN;
case 'n':
valstate=NULL;
expect(JSONUtil.NULL_CHARS);
return NULL;
case -1:
if (getLevel()>0) throw err("Premature EOF");
return EOF;
default: throw err(null);
}
ch = getChar();
}
}
@Override
public String toString() {
return "start="+start+",end="+end+",state="+state+"valstate="+valstate;
}
/** Returns the next event encountered in the JSON stream, one of
* <ul>
* <li>{@link #STRING}</li>
* <li>{@link #LONG}</li>
* <li>{@link #NUMBER}</li>
* <li>{@link #BIGNUMBER}</li>
* <li>{@link #BOOLEAN}</li>
* <li>{@link #NULL}</li>
* <li>{@link #OBJECT_START}</li>
* <li>{@link #OBJECT_END}</li>
* <li>{@link #OBJECT_END}</li>
* <li>{@link #ARRAY_START}</li>
* <li>{@link #ARRAY_END}</li>
* <li>{@link #EOF}</li>
* </ul>
*/
public int nextEvent() throws IOException {
if (valstate==STRING) {
readStringChars2(devNull,start);
}
else if (valstate==BIGNUMBER) {
continueNumber(devNull);
}
valstate=0;
int ch; // TODO: factor out getCharNWS() to here and check speed
switch (state) {
case 0:
return event = next(getCharNWS());
case DID_OBJSTART:
ch = getCharNWS();
if (ch=='}') {
pop();
return event = OBJECT_END;
}
if (ch != '"') {
throw err("Expected string");
}
state = DID_MEMNAME;
valstate = STRING;
return event = STRING;
case DID_MEMNAME:
ch = getCharNWS();
if (ch!=':') {
throw err("Expected key,value separator ':'");
}
state = DID_MEMVAL; // set state first because it might be pushed...
return event = next(getChar());
case DID_MEMVAL:
ch = getCharNWS();
if (ch=='}') {
pop();
return event = OBJECT_END;
} else if (ch!=',') {
throw err("Expected ',' or '}'");
}
ch = getCharNWS();
if (ch != '"') {
throw err("Expected string");
}
state = DID_MEMNAME;
valstate = STRING;
return event = STRING;
case DID_ARRSTART:
ch = getCharNWS();
if (ch==']') {
pop();
return event = ARRAY_END;
}
state = DID_ARRELEM; // set state first, might be pushed...
return event = next(ch);
case DID_ARRELEM:
ch = getCharNWS();
if (ch==']') {
pop();
return event = ARRAY_END;
} else if (ch!=',') {
throw err("Expected ',' or ']'");
}
// state = DID_ARRELEM;
return event = next(getChar());
}
return 0;
}
public int lastEvent() {
return event;
}
public boolean wasKey()
{
return state == DID_MEMNAME;
}
private void goTo(int what) throws IOException {
if (valstate==what) { valstate=0; return; }
if (valstate==0) {
int ev = nextEvent(); // TODO
if (valstate!=what) {
throw err("type mismatch");
}
valstate=0;
}
else {
throw err("type mismatch");
}
}
/** Returns the JSON string value, decoding any escaped characters. */
public String getString() throws IOException {
return getStringChars().toString();
}
/** Returns the characters of a JSON string value, decoding any escaped characters.
* <p/>The underlying buffer of the returned <code>CharArr</code> should *not* be
* modified as it may be shared with the input buffer.
* <p/>The returned <code>CharArr</code> will only be valid up until
* the next JSONParser method is called. Any required data should be
* read before that point.
*/
public CharArr getStringChars() throws IOException {
goTo(STRING);
return readStringChars();
}
/** Reads a JSON string into the output, decoding any escaped characters. */
public void getString(CharArr output) throws IOException {
goTo(STRING);
readStringChars2(output,start);
}
/** Reads a number from the input stream and parses it as a long, only if
* the value will in fact fit into a signed 64 bit integer. */
public long getLong() throws IOException {
goTo(LONG);
return lval;
}
/** Reads a number from the input stream and parses it as a double */
public double getDouble() throws IOException {
return Double.parseDouble(getNumberChars().toString());
}
/** Returns the characters of a JSON numeric value.
* <p/>The underlying buffer of the returned <code>CharArr</code> should *not* be
* modified as it may be shared with the input buffer.
* <p/>The returned <code>CharArr</code> will only be valid up until
* the next JSONParser method is called. Any required data should be
* read before that point.
*/
public CharArr getNumberChars() throws IOException {
int ev=0;
if (valstate==0) ev = nextEvent();
if (valstate == LONG || valstate == NUMBER) {
valstate=0;
return out;
}
else if (valstate==BIGNUMBER) {
continueNumber(out);
valstate=0;
return out;
} else {
throw err("Unexpected " + ev);
}
}
/** Reads a JSON numeric value into the output. */
public void getNumberChars(CharArr output) throws IOException {
int ev=0;
if (valstate==0) ev=nextEvent();
if (valstate == LONG || valstate == NUMBER) output.write(this.out);
else if (valstate==BIGNUMBER) {
continueNumber(output);
} else {
throw err("Unexpected " + ev);
}
valstate=0;
}
/** Reads a boolean value */
public boolean getBoolean() throws IOException {
goTo(BOOLEAN);
return bool;
}
/** Reads a null value */
public void getNull() throws IOException {
goTo(NULL);
}
/**
* @return the current nesting level, the number of parent objects or arrays.
*/
public int getLevel() {
return ptr;
}
public long getPosition()
{
return gpos+start;
}
}

View File

@ -1,162 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.noggit;
/**
*/
public class JSONUtil {
public static final char[] TRUE_CHARS = new char[] {'t','r','u','e'};
public static final char[] FALSE_CHARS = new char[] {'f','a','l','s','e'};
public static final char[] NULL_CHARS = new char[] {'n','u','l','l'};
public static final char[] HEX_CHARS = new char[] {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
public static final char VALUE_SEPARATOR = ',';
public static final char NAME_SEPARATOR = ':';
public static final char OBJECT_START = '{';
public static final char OBJECT_END = '}';
public static final char ARRAY_START = '[';
public static final char ARRAY_END = ']';
public static String toJSON(Object o) {
CharArr out = new CharArr();
new JSONWriter(out).write(o);
return out.toString();
}
/**
* @param o The object to convert to JSON
* @param indentSize The number of space characters to use as an indent (default 2). 0=newlines but no spaces, -1=no indent at all.
* @return Given Object converted to its JSON representation using the given indentSize
*/
public static String toJSON(Object o, int indentSize) {
CharArr out = new CharArr();
new JSONWriter(out,indentSize).write(o);
return out.toString();
}
public static void writeNumber(int number, CharArr out) {
out.write(Integer.toString(number));
}
public static void writeNumber(long number, CharArr out) {
out.write(Long.toString(number));
}
public static void writeNumber(float number, CharArr out) {
out.write(Float.toString(number));
}
public static void writeNumber(double number, CharArr out) {
out.write(Double.toString(number));
}
public static void writeString(CharArr val, CharArr out) {
writeString(val.getArray(), val.getStart(), val.getEnd(), out);
}
public static void writeString(char[] val, int start, int end, CharArr out) {
out.write('"');
writeStringPart(val,start,end,out);
out.write('"');
}
public static void writeString(CharSequence val, int start, int end, CharArr out) {
out.write('"');
writeStringPart(val,start,end,out);
out.write('"');
}
public static void writeStringPart(char[] val, int start, int end, CharArr out) {
for (int i=start; i<end; i++) {
char ch = val[i];
switch(ch) {
case '"':
case '\\':
out.write('\\');
out.write(ch);
break;
case '\r': out.write('\\'); out.write('r'); break;
case '\n': out.write('\\'); out.write('n'); break;
case '\t': out.write('\\'); out.write('t'); break;
case '\b': out.write('\\'); out.write('b'); break;
case '\f': out.write('\\'); out.write('f'); break;
// case '/':
default:
if (ch <= 0x1F) {
unicodeEscape(ch,out);
} else {
// These characters are valid JSON, but not valid JavaScript
if (ch=='\u2028' || ch=='\u2029') {
unicodeEscape(ch,out);
} else {
out.write(ch);
}
}
}
}
}
public static void writeStringPart(CharSequence chars, int start, int end, CharArr out) {
for (int i=start; i<end; i++) {
char ch = chars.charAt(i);
switch(ch) {
case '"':
case '\\':
out.write('\\');
out.write(ch);
break;
case '\r': out.write('\\'); out.write('r'); break;
case '\n': out.write('\\'); out.write('n'); break;
case '\t': out.write('\\'); out.write('t'); break;
case '\b': out.write('\\'); out.write('b'); break;
case '\f': out.write('\\'); out.write('f'); break;
// case '/':
default:
if (ch <= 0x1F) {
unicodeEscape(ch,out);
} else {
// These characters are valid JSON, but not valid JavaScript
if (ch=='\u2028' || ch=='\u2029') {
unicodeEscape(ch,out);
} else {
out.write(ch);
}
}
}
}
}
public static void unicodeEscape(int ch, CharArr out) {
out.write('\\');
out.write('u');
out.write(HEX_CHARS[ch>>>12]);
out.write(HEX_CHARS[(ch>>>8)&0xf]);
out.write(HEX_CHARS[(ch>>>4)&0xf]);
out.write(HEX_CHARS[ch&0xf]);
}
public static void writeNull(CharArr out) {
out.write(NULL_CHARS);
}
public static void writeBoolean(boolean val, CharArr out) {
out.write(val ? TRUE_CHARS : FALSE_CHARS);
}
}

View File

@ -1,342 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.noggit;
import java.util.*;
/**
*/
public class JSONWriter {
/** Implement this interface on your class to support serialization */
public static interface Writable {
public void write(JSONWriter writer);
}
protected int level;
protected int indent;
protected final CharArr out;
/**
* @param out the CharArr to write the output to.
* @param indentSize The number of space characters to use as an indent (default 2). 0=newlines but no spaces, -1=no indent at all.
*/
public JSONWriter(CharArr out, int indentSize) {
this.out = out;
this.indent = indentSize;
}
public JSONWriter(CharArr out) {
this(out, 2);
}
public void setIndentSize(int indentSize) {
this.indent = indentSize;
}
public void indent() {
if (indent >= 0) {
out.write('\n');
if (indent > 0) {
int spaces = level*indent;
out.reserve(spaces);
for (int i=0; i<spaces; i++) {
out.unsafeWrite(' ');
}
}
}
}
public void write(Object o) {
if (o == null) {
writeNull();
} else if (o instanceof CharSequence) {
writeString((CharSequence)o);
} else if (o instanceof Number) {
if (o instanceof Integer || o instanceof Long) {
write(((Number)o).longValue());
} else if (o instanceof Float || o instanceof Double) {
write(((Number)o).doubleValue());
} else {
CharArr arr = new CharArr();
arr.write(o.toString());
writeNumber(arr);
}
} else if (o instanceof Map) {
write((Map)o);
} else if (o instanceof Collection) {
write((Collection)o);
} else if (o instanceof Object[]) {
write(Arrays.asList((Object[])o));
} else if (o instanceof Boolean) {
write(((Boolean)o).booleanValue());
} else if (o instanceof Writable) {
((Writable) o).write(this);
}
else if (o instanceof int[]) {
write((int[])o);
} else if (o instanceof float[]) {
write((float[])o);
} else if (o instanceof long[]) {
write((long[])o);
} else if (o instanceof double[]) {
write((double[])o);
} else if (o instanceof short[]) {
write((short[])o);
} else if (o instanceof boolean[]) {
write((boolean[])o);
} else if (o instanceof char[]) {
write((char[])o);
} else if (o instanceof byte[]) {
write((byte[])o);
} else {
handleUnknownClass(o);
}
}
/** Override this method for custom handling of unknown classes. Also see the Writable interface. */
public void handleUnknownClass(Object o) {
writeString(out.toString());
}
public void write(Map val) {
startObject();
int sz = val.size();
boolean first = true;
for (Map.Entry entry : (Set<Map.Entry>)val.entrySet()) {
if (first) {
first = false;
} else {
writeValueSeparator();
}
if (sz>1) indent();
writeString(entry.getKey().toString());
writeNameSeparator();
write(entry.getValue());
}
endObject();
}
public void write(Collection val) {
startArray();
int sz = val.size();
boolean first = true;
for (Object o : val) {
if (first) {
first = false;
} else {
writeValueSeparator();
}
if (sz>1) indent();
write(o);
}
endArray();
}
/** A byte[] may be either a single logical value, or a list of small integers.
* It's up to the implementation to decide.
*/
public void write(byte[] val) {
startArray();
boolean first = true;
for (short v : val) {
if (first) {
first = false;
} else {
writeValueSeparator();
}
write(v);
}
endArray();
}
public void write(short[] val) {
startArray();
boolean first = true;
for (short v : val) {
if (first) {
first = false;
} else {
writeValueSeparator();
}
write(v);
}
endArray();
}
public void write(int[] val) {
startArray();
boolean first = true;
for (int v : val) {
if (first) {
first = false;
} else {
writeValueSeparator();
}
write(v);
}
endArray();
}
public void write(long[] val) {
startArray();
boolean first = true;
for (long v : val) {
if (first) {
first = false;
} else {
writeValueSeparator();
}
write(v);
}
endArray();
}
public void write(float[] val) {
startArray();
boolean first = true;
for (float v : val) {
if (first) {
first = false;
} else {
writeValueSeparator();
}
write(v);
}
endArray();
}
public void write(double[] val) {
startArray();
boolean first = true;
for (double v : val) {
if (first) {
first = false;
} else {
writeValueSeparator();
}
write(v);
}
endArray();
}
public void write(boolean[] val) {
startArray();
boolean first = true;
for (boolean v : val) {
if (first) {
first = false;
} else {
writeValueSeparator();
}
write(v);
}
endArray();
}
public void write(short number) { write ((int)number); }
public void write(byte number) { write((int)number); }
public void writeNull() {
JSONUtil.writeNull(out);
}
public void writeString(CharSequence str) {
JSONUtil.writeString(str,0,str.length(),out);
}
public void writeString(CharArr str) {
JSONUtil.writeString(str,out);
}
public void writeStringStart() {
out.write('"');
}
public void writeStringChars(CharArr partialStr) {
JSONUtil.writeStringPart(partialStr.getArray(), partialStr.getStart(), partialStr.getEnd(), out);
}
public void writeStringEnd() {
out.write('"');
}
public void write(long number) {
JSONUtil.writeNumber(number,out);
}
public void write(int number) {
JSONUtil.writeNumber(number,out);
}
public void write(double number) {
JSONUtil.writeNumber(number,out);
}
public void write(float number) {
JSONUtil.writeNumber(number,out);
}
public void write(boolean bool) {
JSONUtil.writeBoolean(bool,out);
}
public void write(char[] val) {
JSONUtil.writeString(val, 0, val.length, out);
}
public void writeNumber(CharArr digits) {
out.write(digits);
}
public void writePartialNumber(CharArr digits) {
out.write(digits);
}
public void startObject() {
out.write('{');
level++;
}
public void endObject() {
out.write('}');
level--;
}
public void startArray() {
out.write('[');
level++;
}
public void endArray() {
out.write(']');
level--;
}
public void writeValueSeparator() {
out.write(',');
}
public void writeNameSeparator() {
out.write(':');
}
}

View File

@ -1,152 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.noggit;
import java.util.*;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
/**
*/
public class ObjectBuilder {
public static Object fromJSON(String json) throws IOException {
JSONParser p = new JSONParser(json);
return getVal(p);
}
public static Object getVal(JSONParser parser) throws IOException {
return new ObjectBuilder(parser).getVal();
}
final JSONParser parser;
public ObjectBuilder(JSONParser parser) throws IOException {
this.parser = parser;
if (parser.lastEvent()==0) parser.nextEvent();
}
public Object getVal() throws IOException {
int ev = parser.lastEvent();
switch(ev) {
case JSONParser.STRING: return getString();
case JSONParser.LONG: return getLong();
case JSONParser.NUMBER: return getNumber();
case JSONParser.BIGNUMBER: return getBigNumber();
case JSONParser.BOOLEAN: return getBoolean();
case JSONParser.NULL: return getNull();
case JSONParser.OBJECT_START: return getObject();
case JSONParser.OBJECT_END: return null; // OR ERROR?
case JSONParser.ARRAY_START: return getArray();
case JSONParser.ARRAY_END: return null; // OR ERROR?
case JSONParser.EOF: return null; // OR ERROR?
default: return null; // OR ERROR?
}
}
public Object getString() throws IOException {
return parser.getString();
}
public Object getLong() throws IOException {
return Long.valueOf(parser.getLong());
}
public Object getNumber() throws IOException {
CharArr num = parser.getNumberChars();
String numstr = num.toString();
double d = Double.parseDouble(numstr);
if (!Double.isInfinite(d)) return Double.valueOf(d);
// TODO: use more efficient constructor in Java5
return new BigDecimal(numstr);
}
public Object getBigNumber() throws IOException {
CharArr num = parser.getNumberChars();
String numstr = num.toString();
for(int ch; (ch=num.read())!=-1;) {
if (ch=='.' || ch=='e' || ch=='E') return new BigDecimal(numstr);
}
return new BigInteger(numstr);
}
public Object getBoolean() throws IOException {
return parser.getBoolean();
}
public Object getNull() throws IOException {
parser.getNull();
return null;
}
public Object newObject() throws IOException {
return new LinkedHashMap();
}
public Object getKey() throws IOException {
return parser.getString();
}
public void addKeyVal(Object map, Object key, Object val) throws IOException {
Object prev = ((Map)map).put(key,val);
// TODO: test for repeated value?
}
public Object objectEnd(Object obj) {
return obj;
}
public Object getObject() throws IOException {
Object m = newObject();
for(;;) {
int ev = parser.nextEvent();
if (ev==JSONParser.OBJECT_END) return objectEnd(m);
Object key = getKey();
ev = parser.nextEvent();
Object val = getVal();
addKeyVal(m, key, val);
}
}
public Object newArray() {
return new ArrayList();
}
public void addArrayVal(Object arr, Object val) throws IOException {
((List)arr).add(val);
}
public Object endArray(Object arr) {
return arr;
}
public Object getArray() throws IOException {
Object arr = newArray();
for(;;) {
int ev = parser.nextEvent();
if (ev==JSONParser.ARRAY_END) return endArray(arr);
Object val = getVal();
addArrayVal(arr, val);
}
}
}

View File

@ -1,22 +0,0 @@
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.
-->
<html>
<body>
JSON streaming parser and serializer.
</body>
</html>

View File

@ -26,7 +26,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.noggit.JSONWriter;
import org.noggit.JSONWriter;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.zookeeper.KeeperException;

View File

@ -17,8 +17,8 @@ package org.apache.solr.common.cloud;
* limitations under the License.
*/
import org.apache.noggit.JSONUtil;
import org.apache.noggit.JSONWriter;
import org.noggit.JSONUtil;
import org.noggit.JSONWriter;
import java.util.Collection;
import java.util.Collections;

View File

@ -17,7 +17,7 @@ package org.apache.solr.common.cloud;
* limitations under the License.
*/
import org.apache.noggit.JSONWriter;
import org.noggit.JSONWriter;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.SolrParams;

View File

@ -17,7 +17,7 @@ package org.apache.solr.common.cloud;
* limitations under the License.
*/
import org.apache.noggit.JSONUtil;
import org.noggit.JSONUtil;
import java.util.Map;

View File

@ -17,8 +17,8 @@ package org.apache.solr.common.cloud;
* limitations under the License.
*/
import org.apache.noggit.JSONUtil;
import org.apache.noggit.JSONWriter;
import org.noggit.JSONUtil;
import org.noggit.JSONWriter;
import java.util.Collection;
import java.util.HashMap;

View File

@ -17,8 +17,8 @@ package org.apache.solr.common.cloud;
* limitations under the License.
*/
import org.apache.noggit.JSONUtil;
import org.apache.noggit.JSONWriter;
import org.noggit.JSONUtil;
import org.noggit.JSONWriter;
import java.util.Collections;
import java.util.HashMap;

View File

@ -31,10 +31,10 @@ import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.apache.noggit.CharArr;
import org.apache.noggit.JSONParser;
import org.apache.noggit.JSONWriter;
import org.apache.noggit.ObjectBuilder;
import org.noggit.CharArr;
import org.noggit.JSONParser;
import org.noggit.JSONWriter;
import org.noggit.ObjectBuilder;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.util.ByteUtils;

View File

@ -17,7 +17,7 @@
package org.apache.solr.common.util;
import org.apache.noggit.CharArr;
import org.noggit.CharArr;
public class ByteUtils {

View File

@ -16,7 +16,7 @@
*/
package org.apache.solr.common.util;
import org.apache.noggit.CharArr;
import org.noggit.CharArr;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;

View File

@ -17,7 +17,7 @@
package org.apache.solr;
import org.apache.noggit.ObjectBuilder;
import org.noggit.ObjectBuilder;
import org.apache.solr.common.util.StrUtils;
import java.util.*;

View File

@ -26,7 +26,6 @@ import javax.xml.xpath.XPathExpressionException;
import org.apache.lucene.util.Constants;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.QuickPatchThreadsFilter;
import org.apache.noggit.*;
import org.apache.solr.client.solrj.util.ClientUtils;
import org.apache.solr.common.*;
import org.apache.solr.common.cloud.SolrZkClient;
@ -47,6 +46,9 @@ import org.apache.solr.util.TestHarness;
import org.junit.*;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.noggit.CharArr;
import org.noggit.JSONUtil;
import org.noggit.ObjectBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;