/* * Copyright 2008-2016 the original author or authors. * * 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 com.nominanuda.zen.obj; import static com.nominanuda.zen.common.Ex.EX; import static com.nominanuda.zen.common.Str.UTF8; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.io.UncheckedIOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.util.Arrays; import javax.annotation.concurrent.ThreadSafe; import com.nominanuda.zen.common.Str; import com.nominanuda.zen.oio.ReaderInputStream; import com.nominanuda.zen.reactivestreams.SubscriptionImpl; @ThreadSafe public class JsonDeserializer { public static final JsonDeserializer JSON_DESERIALIZER = new JsonDeserializer(); private final int readBufSize = 8192; public Object deserialize(InputStream is) throws UncheckedIOException { AnyNioDeserializer d = new AnyNioDeserializer(); d.onSubscribe(new SubscriptionImpl()); byte[] buf = new byte[readBufSize]; int nread = 0; try { while((nread = is.read(buf)) >= 0) { if(nread == 0) { continue; } else { d.onNext(ByteBuffer.wrap(Arrays.copyOf(buf, nread))); } } d.onComplete(); } catch (IOException e) { d.onError(e); throw EX.uncheckedIO(e); } return d.get().toJavaObjModel(); } public Object deserialize(byte[] barr) { return deserialize(ByteBuffer.wrap(barr)); } public Object deserialize(ByteBuffer bb) { return deserializeToAny(bb).toJavaObjModel(); } public Any deserializeToAny(ByteBuffer bb) { AnyNioDeserializer d = new AnyNioDeserializer(); d.onSubscribe(new SubscriptionImpl()); d.onNext(bb); d.onComplete(); return d.get(); } public Object deserializeVal(ByteBuffer bb) { AnyNioDeserializer d = new AnyNioDeserializer(); d.onSubscribe(new SubscriptionImpl()); d.onNext(bb); d.onComplete(); return d.get().toJavaObjModel(); } public Object deserialize(Reader r) { return deserialize(new ReaderInputStream(r, UTF8)); } public Object deserialize(String s) { return deserialize(s.getBytes(UTF8)); } //TODO faster and less new() public Number deserializeNumber(String s) { if(s.indexOf('.') >= 0 || s.indexOf('e') >= 0 || s.indexOf('E') >= 0) { return Double.valueOf(s); } else { Long l = Long.valueOf(s); if(l > Integer.MAX_VALUE || l <Integer.MIN_VALUE) { return l; } else { return new Integer(l.intValue()); } } } public String decodeString(ByteBuffer nioBuffer) throws IllegalArgumentException { CharBuffer cbuf = Str.UTF8.decode(nioBuffer); int len = cbuf.length(); int widx = 0; for(int ridx = 1; ridx < len - 1; ridx++) { char c = cbuf.get(ridx); if('\\' == c) { if(ridx > len - 2) { throw new IllegalArgumentException("spare \\ at the end of stream"); } ridx++; char c1 = cbuf.get(ridx); switch (c1) { case 'b': cbuf.put(widx++, '\b'); break; case 't': cbuf.put(widx++, '\t'); break; case 'n': cbuf.put(widx++, '\n'); break; case 'f': cbuf.put(widx++, '\f'); break; case 'r': cbuf.put(widx++, '\r'); break; case '\'': cbuf.put(widx++, '\''); break; case '\"': cbuf.put(widx++, '"'); break; case '\\': cbuf.put(widx++, '\\'); break; case '/': cbuf.put(widx++, '/'); break; case 'u': char unicode = parseUnicode(cbuf.get(++ridx),cbuf.get(++ridx),cbuf.get(++ridx),cbuf.get(++ridx)); cbuf.put(widx++, unicode); break; default: throw new IllegalArgumentException("unrecognized escape sequence start "+c1); } } else { switch (c) { case '"': throw new IllegalArgumentException("unescaped double quote in string literal"); default: cbuf.put(widx++, c); break; } } } return new String(cbuf.array(), 0, widx); } private char parseUnicode(char c0, char c1, char c2, char c3) { String s = new String(new char[] {c0,c1,c2,c3}); return (char)Integer.parseInt(s, 16); } }