Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 1 | package aQute.lib.json; |
| 2 | |
| 3 | import java.io.*; |
| 4 | import java.lang.reflect.*; |
| 5 | import java.security.*; |
| 6 | import java.util.*; |
Stuart McCulloch | d602fe1 | 2012-07-20 16:50:39 +0000 | [diff] [blame] | 7 | import java.util.zip.*; |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 8 | |
| 9 | public class Encoder implements Appendable, Closeable, Flushable { |
| 10 | final JSONCodec codec; |
| 11 | Appendable app; |
| 12 | MessageDigest digest; |
| 13 | boolean writeDefaults; |
| 14 | String encoding = "UTF-8"; |
Stuart McCulloch | d602fe1 | 2012-07-20 16:50:39 +0000 | [diff] [blame] | 15 | boolean deflate; |
| 16 | |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 17 | Encoder(JSONCodec codec) { |
| 18 | this.codec = codec; |
| 19 | } |
| 20 | |
| 21 | public Encoder put(Object object) throws Exception { |
| 22 | if (app == null) |
| 23 | to(); |
| 24 | |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame] | 25 | codec.encode(this, object, null, new IdentityHashMap<Object,Type>()); |
Stuart McCulloch | d602fe1 | 2012-07-20 16:50:39 +0000 | [diff] [blame] | 26 | flush(); |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 27 | return this; |
| 28 | } |
| 29 | |
| 30 | public Encoder mark() throws NoSuchAlgorithmException { |
| 31 | if (digest == null) |
| 32 | digest = MessageDigest.getInstance("SHA1"); |
| 33 | digest.reset(); |
| 34 | return this; |
| 35 | } |
| 36 | |
| 37 | public byte[] digest() throws NoSuchAlgorithmException, IOException { |
| 38 | if (digest == null) |
| 39 | return null; |
| 40 | append('\n'); |
| 41 | return digest.digest(); |
| 42 | } |
| 43 | |
| 44 | public Encoder to() throws IOException { |
| 45 | to(new StringWriter()); |
| 46 | return this; |
| 47 | } |
| 48 | |
| 49 | public Encoder to(File file) throws IOException { |
| 50 | return to(new FileOutputStream(file)); |
| 51 | } |
| 52 | |
| 53 | public Encoder charset(String encoding) { |
| 54 | this.encoding = encoding; |
| 55 | return this; |
| 56 | } |
| 57 | |
| 58 | public Encoder to(OutputStream out) throws IOException { |
Stuart McCulloch | d602fe1 | 2012-07-20 16:50:39 +0000 | [diff] [blame] | 59 | if ( deflate) |
| 60 | out = new DeflaterOutputStream(out); |
| 61 | |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 62 | return to(new OutputStreamWriter(out, encoding)); |
| 63 | } |
| 64 | |
| 65 | public Encoder to(Appendable out) throws IOException { |
| 66 | app = out; |
| 67 | return this; |
| 68 | } |
| 69 | |
| 70 | public Appendable append(char c) throws IOException { |
| 71 | if (digest != null) { |
| 72 | digest.update((byte) (c / 256)); |
| 73 | digest.update((byte) (c % 256)); |
| 74 | } |
| 75 | app.append(c); |
| 76 | return this; |
| 77 | } |
| 78 | |
| 79 | public Appendable append(CharSequence sq) throws IOException { |
| 80 | return append(sq, 0, sq.length()); |
| 81 | } |
| 82 | |
| 83 | public Appendable append(CharSequence sq, int start, int length) throws IOException { |
| 84 | if (digest != null) { |
| 85 | for (int i = start; i < length; i++) { |
| 86 | char c = sq.charAt(i); |
| 87 | digest.update((byte) (c / 256)); |
| 88 | digest.update((byte) (c % 256)); |
| 89 | } |
| 90 | } |
| 91 | app.append(sq, start, length); |
| 92 | return this; |
| 93 | } |
| 94 | |
Stuart McCulloch | 55d4dfe | 2012-08-07 10:57:21 +0000 | [diff] [blame] | 95 | @Override |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 96 | public String toString() { |
| 97 | return app.toString(); |
| 98 | } |
| 99 | |
| 100 | public void close() throws IOException { |
| 101 | if (app != null && app instanceof Closeable) |
| 102 | ((Closeable) app).close(); |
| 103 | } |
| 104 | |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame] | 105 | void encode(Object object, Type type, Map<Object,Type> visited) throws Exception { |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 106 | codec.encode(this, object, type, visited); |
| 107 | } |
| 108 | |
| 109 | public Encoder writeDefaults() { |
| 110 | writeDefaults = true; |
| 111 | return this; |
| 112 | } |
| 113 | |
| 114 | public void flush() throws IOException { |
| 115 | if (app instanceof Flushable) { |
| 116 | ((Flushable) app).flush(); |
| 117 | } |
| 118 | } |
Stuart McCulloch | d602fe1 | 2012-07-20 16:50:39 +0000 | [diff] [blame] | 119 | public Encoder deflate() { |
| 120 | if ( app != null) |
| 121 | throw new IllegalStateException("Writer already set, deflate must come before to(...)"); |
| 122 | deflate = true; |
| 123 | return this; |
| 124 | } |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 125 | } |