http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/ab8f0faa/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlParserSession.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlParserSession.java new file mode 100644 index 0000000..62de10e --- /dev/null +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlParserSession.java @@ -0,0 +1,669 @@ +// *************************************************************************************************************************** +// * 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.juneau.yaml.proto; + +import static org.apache.juneau.internal.StringUtils.*; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; + +import org.apache.juneau.*; +import org.apache.juneau.internal.*; +import org.apache.juneau.parser.*; +import org.apache.juneau.transform.*; + +/** + * Session object that lives for the duration of a single use of {@link YamlParser}. + * + * <p> + * This class is NOT thread safe. + * It is typically discarded after one-time use although it can be reused against multiple inputs. + */ +@SuppressWarnings({ "unchecked", "rawtypes" }) +public final class YamlParserSession extends ReaderParserSession { + + private static final AsciiSet decChars = new AsciiSet("0123456789"); + + /** + * Create a new session using properties specified in the context. + * + * @param ctx + * The context creating this session object. + * The context contains all the configuration settings for this object. + * @param args + * Runtime session arguments. + */ + protected YamlParserSession(YamlParserContext ctx, ParserSessionArgs args) { + super(ctx, args); + } + + /** + * Returns <jk>true</jk> if the specified character is whitespace. + * + * <p> + * The definition of whitespace is different for strict vs lax mode. + * Strict mode only interprets 0x20 (space), 0x09 (tab), 0x0A (line feed) and 0x0D (carriage return) as whitespace. + * Lax mode uses {@link Character#isWhitespace(int)} to make the determination. + * + * @param cp The codepoint. + * @return <jk>true</jk> if the specified character is whitespace. + */ + protected final boolean isWhitespace(int cp) { + if (isStrict()) + return cp <= 0x20 && (cp == 0x09 || cp == 0x0A || cp == 0x0D || cp == 0x20); + return Character.isWhitespace(cp); + } + + /** + * Returns <jk>true</jk> if the specified character is whitespace or '/'. + * + * @param cp The codepoint. + * @return <jk>true</jk> if the specified character is whitespace or '/'. + */ + protected final boolean isCommentOrWhitespace(int cp) { + if (cp == '/') + return true; + if (isStrict()) + return cp <= 0x20 && (cp == 0x09 || cp == 0x0A || cp == 0x0D || cp == 0x20); + return Character.isWhitespace(cp); + } + + @Override /* ParserSession */ + protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws Exception { + ParserReader r = pipe.getParserReader(); + if (r == null) + return null; + T o = parseAnything(type, r, getOuter(), null); + validateEnd(r); + return o; + } + + @Override /* ReaderParserSession */ + protected <K,V> Map<K,V> doParseIntoMap(ParserPipe pipe, Map<K,V> m, Type keyType, Type valueType) throws Exception { + ParserReader r = pipe.getParserReader(); + m = parseIntoMap2(r, m, (ClassMeta<K>)getClassMeta(keyType), (ClassMeta<V>)getClassMeta(valueType), null); + validateEnd(r); + return m; + } + + @Override /* ReaderParserSession */ + protected <E> Collection<E> doParseIntoCollection(ParserPipe pipe, Collection<E> c, Type elementType) throws Exception { + ParserReader r = pipe.getParserReader(); + c = parseIntoCollection2(r, c, getClassMeta(elementType), null); + validateEnd(r); + return c; + } + + private <T> T parseAnything(ClassMeta<T> eType, ParserReader r, Object outer, BeanPropertyMeta pMeta) throws Exception { + + if (eType == null) + eType = (ClassMeta<T>)object(); + PojoSwap<T,Object> swap = (PojoSwap<T,Object>)eType.getPojoSwap(this); + ClassMeta<?> sType = swap == null ? eType : swap.getSwapClassMeta(this); + setCurrentClass(sType); + + Object o = null; + + skipCommentsAndSpace(r); + int c = r.peek(); + if (c == -1) { + if (isStrict()) + throw new ParseException(r.getLocation(this), "Empty input."); + // Let o be null. + } else if ((c == ',' || c == '}' || c == ']')) { + if (isStrict()) + throw new ParseException(r.getLocation(this), "Missing value detected."); + // Handle bug in Cognos 10.2.1 that can product non-existent values. + // Let o be null; + } else if (c == 'n') { + parseKeyword("null", r); + } else if (sType.isObject()) { + if (c == '{') { + ObjectMap m2 = new ObjectMap(this); + parseIntoMap2(r, m2, string(), object(), pMeta); + o = cast(m2, pMeta, eType); + } else if (c == '[') { + o = parseIntoCollection2(r, new ObjectList(this), object(), pMeta); + } else if (c == '\'' || c == '"') { + o = parseString(r); + if (sType.isChar()) + o = o.toString().charAt(0); + } else if (c >= '0' && c <= '9' || c == '-' || c == '.') { + o = parseNumber(r, null); + } else if (c == 't') { + parseKeyword("true", r); + o = Boolean.TRUE; + } else { + parseKeyword("false", r); + o = Boolean.FALSE; + } + } else if (sType.isBoolean()) { + o = parseBoolean(r); + } else if (sType.isCharSequence()) { + o = parseString(r); + } else if (sType.isChar()) { + o = parseString(r).charAt(0); + } else if (sType.isNumber()) { + o = parseNumber(r, (Class<? extends Number>)sType.getInnerClass()); + } else if (sType.isMap()) { + Map m = (sType.canCreateNewInstance(outer) ? (Map)sType.newInstance(outer) : new ObjectMap(this)); + o = parseIntoMap2(r, m, sType.getKeyType(), sType.getValueType(), pMeta); + } else if (sType.isCollection()) { + if (c == '{') { + ObjectMap m = new ObjectMap(this); + parseIntoMap2(r, m, string(), object(), pMeta); + o = cast(m, pMeta, eType); + } else { + Collection l = (sType.canCreateNewInstance(outer) ? (Collection)sType.newInstance() : new ObjectList(this)); + o = parseIntoCollection2(r, l, sType, pMeta); + } + } else if (sType.canCreateNewBean(outer)) { + BeanMap m = newBeanMap(outer, sType.getInnerClass()); + o = parseIntoBeanMap2(r, m).getBean(); + } else if (sType.canCreateNewInstanceFromString(outer) && (c == '\'' || c == '"')) { + o = sType.newInstanceFromString(outer, parseString(r)); + } else if (sType.canCreateNewInstanceFromNumber(outer) && isFirstNumberChar((char)c)) { + o = sType.newInstanceFromNumber(this, outer, parseNumber(r, sType.getNewInstanceFromNumberClass())); + } else if (sType.isArray() || sType.isArgs()) { + if (c == '{') { + ObjectMap m = new ObjectMap(this); + parseIntoMap2(r, m, string(), object(), pMeta); + o = cast(m, pMeta, eType); + } else { + ArrayList l = (ArrayList)parseIntoCollection2(r, new ArrayList(), sType, pMeta); + o = toArray(sType, l); + } + } else if (c == '{') { + Map m = new ObjectMap(this); + parseIntoMap2(r, m, sType.getKeyType(), sType.getValueType(), pMeta); + if (m.containsKey(getBeanTypePropertyName(eType))) + o = cast((ObjectMap)m, pMeta, eType); + else + throw new ParseException(r.getLocation(this), "Class ''{0}'' could not be instantiated. Reason: ''{1}''", + sType.getInnerClass().getName(), sType.getNotABeanReason()); + } else if (sType.canCreateNewInstanceFromString(outer) && ! isStrict()) { + o = sType.newInstanceFromString(outer, parseString(r)); + } else { + throw new ParseException(r.getLocation(this), "Unrecognized syntax for class type ''{0}'', starting character ''{1}''", + sType, (char)c); + } + + if (swap != null && o != null) + o = swap.unswap(this, o, eType); + + if (outer != null) + setParent(eType, o, outer); + + return (T)o; + } + + private Number parseNumber(ParserReader r, Class<? extends Number> type) throws Exception { + int c = r.peek(); + if (c == '\'' || c == '"') + return parseNumber(r, parseString(r), type); + return parseNumber(r, parseNumberString(r), type); + } + + private Number parseNumber(ParserReader r, String s, Class<? extends Number> type) throws Exception { + + // JSON has slightly different number rules from Java. + // Strict mode enforces these different rules, lax does not. + if (isStrict()) { + + // Lax allows blank strings to represent 0. + // Strict does not allow blank strings. + if (s.length() == 0) + throw new ParseException(r.getLocation(this), "Invalid JSON number: ''{0}''", s); + + // Need to weed out octal and hexadecimal formats: 0123,-0123,0x123,-0x123. + // Don't weed out 0 or -0. + boolean isNegative = false; + char c = s.charAt(0); + if (c == '-') { + isNegative = true; + c = (s.length() == 1 ? 'x' : s.charAt(1)); + } + + // JSON doesn't allow '.123' and '-.123'. + if (c == '.') + throw new ParseException(loc(r), "Invalid JSON number: ''{0}''", s); + + // '01' is not a valid number, but '0.1', '0e1', '0e+1' are valid. + if (c == '0' && s.length() > (isNegative ? 2 : 1)) { + char c2 = s.charAt((isNegative ? 2 : 1)); + if (c2 != '.' && c2 != 'e' && c2 != 'E') + throw new ParseException(loc(r), "Invalid JSON number: ''{0}''", s); + } + + // JSON doesn't allow '1.' or '0.e1'. + int i = s.indexOf('.'); + if (i != -1 && (s.length() == (i+1) || ! decChars.contains(s.charAt(i+1)))) + throw new ParseException(loc(r), "Invalid JSON number: ''{0}''", s); + + } + return StringUtils.parseNumber(s, type); + } + + private Boolean parseBoolean(ParserReader r) throws Exception { + int c = r.peek(); + if (c == '\'' || c == '"') + return Boolean.valueOf(parseString(r)); + if (c == 't') { + parseKeyword("true", r); + return Boolean.TRUE; + } + parseKeyword("false", r); + return Boolean.FALSE; + } + + + private <K,V> Map<K,V> parseIntoMap2(ParserReader r, Map<K,V> m, ClassMeta<K> keyType, + ClassMeta<V> valueType, BeanPropertyMeta pMeta) throws Exception { + + if (keyType == null) + keyType = (ClassMeta<K>)string(); + + int S0=0; // Looking for outer { + int S1=1; // Looking for attrName start. + int S3=3; // Found attrName end, looking for :. + int S4=4; // Found :, looking for valStart: { [ " ' LITERAL. + int S5=5; // Looking for , or } + int S6=6; // Found , looking for attr start. + + int state = S0; + String currAttr = null; + int c = 0; + while (c != -1) { + c = r.read(); + if (state == S0) { + if (c == '{') + state = S1; + } else if (state == S1) { + if (c == '}') { + return m; + } else if (isCommentOrWhitespace(c)) { + skipCommentsAndSpace(r.unread()); + } else { + currAttr = parseFieldName(r.unread()); + state = S3; + } + } else if (state == S3) { + if (c == ':') + state = S4; + } else if (state == S4) { + if (isCommentOrWhitespace(c)) { + skipCommentsAndSpace(r.unread()); + } else { + K key = convertAttrToType(m, currAttr, keyType); + V value = parseAnything(valueType, r.unread(), m, pMeta); + setName(valueType, value, key); + m.put(key, value); + state = S5; + } + } else if (state == S5) { + if (c == ',') + state = S6; + else if (isCommentOrWhitespace(c)) + skipCommentsAndSpace(r.unread()); + else if (c == '}') { + return m; + } else { + break; + } + } else if (state == S6) { + if (c == '}') { + break; + } else if (isCommentOrWhitespace(c)) { + skipCommentsAndSpace(r.unread()); + } else { + currAttr = parseFieldName(r.unread()); + state = S3; + } + } + } + if (state == S0) + throw new ParseException(loc(r), "Expected '{' at beginning of JSON object."); + if (state == S1) + throw new ParseException(loc(r), "Could not find attribute name on JSON object."); + if (state == S3) + throw new ParseException(loc(r), "Could not find ':' following attribute name on JSON object."); + if (state == S4) + throw new ParseException(loc(r), "Expected one of the following characters: {,[,',\",LITERAL."); + if (state == S5) + throw new ParseException(loc(r), "Could not find '}' marking end of JSON object."); + if (state == S6) + throw new ParseException(loc(r), "Unexpected '}' found in JSON object."); + + return null; // Unreachable. + } + + /* + * Parse a JSON attribute from the character array at the specified position, then + * set the position marker to the last character in the field name. + */ + private String parseFieldName(ParserReader r) throws Exception { + int c = r.peek(); + if (c == '\'' || c == '"') + return parseString(r); + if (isStrict()) + throw new ParseException(loc(r), "Unquoted attribute detected."); + r.mark(); + // Look for whitespace. + while (c != -1) { + c = r.read(); + if (c == ':' || isWhitespace(c) || c == '/') { + r.unread(); + String s = r.getMarked().intern(); + return s.equals("null") ? null : s; + } + } + throw new ParseException(loc(r), "Could not find the end of the field name."); + } + + private <E> Collection<E> parseIntoCollection2(ParserReader r, Collection<E> l, + ClassMeta<?> type, BeanPropertyMeta pMeta) throws Exception { + + int S0=0; // Looking for outermost [ + int S1=1; // Looking for starting [ or { or " or ' or LITERAL or ] + int S2=2; // Looking for , or ] + int S3=3; // Looking for starting [ or { or " or ' or LITERAL + + int argIndex = 0; + + int state = S0; + int c = 0; + while (c != -1) { + c = r.read(); + if (state == S0) { + if (c == '[') + state = S1; + } else if (state == S1) { + if (c == ']') { + return l; + } else if (isCommentOrWhitespace(c)) { + skipCommentsAndSpace(r.unread()); + } else if (c != -1) { + l.add((E)parseAnything(type.isArgs() ? type.getArg(argIndex++) : type.getElementType(), r.unread(), l, pMeta)); + state = S2; + } + } else if (state == S2) { + if (c == ',') { + state = S3; + } else if (isCommentOrWhitespace(c)) { + skipCommentsAndSpace(r.unread()); + } else if (c == ']') { + return l; + } else { + break; // Invalid character found. + } + } else if (state == S3) { + if (isCommentOrWhitespace(c)) { + skipCommentsAndSpace(r.unread()); + } else if (c == ']') { + break; + } else if (c != -1) { + l.add((E)parseAnything(type.isArgs() ? type.getArg(argIndex++) : type.getElementType(), r.unread(), l, pMeta)); + state = S2; + } + } + } + if (state == S0) + throw new ParseException(loc(r), "Expected '[' at beginning of JSON array."); + if (state == S1) + throw new ParseException(loc(r), "Expected one of the following characters: {,[,',\",LITERAL."); + if (state == S2) + throw new ParseException(loc(r), "Expected ',' or ']'."); + if (state == S3) + throw new ParseException(loc(r), "Unexpected trailing comma in array."); + + return null; // Unreachable. + } + + private <T> BeanMap<T> parseIntoBeanMap2(ParserReader r, BeanMap<T> m) throws Exception { + + int S0=0; // Looking for outer { + int S1=1; // Looking for attrName start. + int S3=3; // Found attrName end, looking for :. + int S4=4; // Found :, looking for valStart: { [ " ' LITERAL. + int S5=5; // Looking for , or } + + int state = S0; + String currAttr = ""; + int c = 0; + int currAttrLine = -1, currAttrCol = -1; + while (c != -1) { + c = r.read(); + if (state == S0) { + if (c == '{') + state = S1; + } else if (state == S1) { + if (c == '}') { + return m; + } else if (isCommentOrWhitespace(c)) { + skipCommentsAndSpace(r.unread()); + } else { + r.unread(); + currAttrLine= r.getLine(); + currAttrCol = r.getColumn(); + currAttr = parseFieldName(r); + state = S3; + } + } else if (state == S3) { + if (c == ':') + state = S4; + } else if (state == S4) { + if (isCommentOrWhitespace(c)) { + skipCommentsAndSpace(r.unread()); + } else { + if (! currAttr.equals(getBeanTypePropertyName(m.getClassMeta()))) { + BeanPropertyMeta pMeta = m.getPropertyMeta(currAttr); + setCurrentProperty(pMeta); + if (pMeta == null) { + onUnknownProperty(r.getPipe(), currAttr, m, currAttrLine, currAttrCol); + parseAnything(object(), r.unread(), m.getBean(false), null); // Read content anyway to ignore it + } else { + ClassMeta<?> cm = pMeta.getClassMeta(); + Object value = parseAnything(cm, r.unread(), m.getBean(false), pMeta); + setName(cm, value, currAttr); + pMeta.set(m, currAttr, value); + } + setCurrentProperty(null); + } + state = S5; + } + } else if (state == S5) { + if (c == ',') + state = S1; + else if (isCommentOrWhitespace(c)) + skipCommentsAndSpace(r.unread()); + else if (c == '}') { + return m; + } + } + } + if (state == S0) + throw new ParseException(loc(r), "Expected '{' at beginning of JSON object."); + if (state == S1) + throw new ParseException(loc(r), "Could not find attribute name on JSON object."); + if (state == S3) + throw new ParseException(loc(r), "Could not find ':' following attribute name on JSON object."); + if (state == S4) + throw new ParseException(loc(r), "Expected one of the following characters: {,[,',\",LITERAL."); + if (state == S5) + throw new ParseException(loc(r), "Could not find '}' marking end of JSON object."); + + return null; // Unreachable. + } + + /* + * Starting from the specified position in the character array, returns the + * position of the character " or '. + * If the string consists of a concatenation of strings (e.g. 'AAA' + "BBB"), this method + * will automatically concatenate the strings and return the result. + */ + private String parseString(ParserReader r) throws Exception { + r.mark(); + int qc = r.read(); // The quote character being used (" or ') + if (qc != '"' && isStrict()) { + String msg = ( + qc == '\'' + ? "Invalid quote character \"{0}\" being used." + : "Did not find quote character marking beginning of string. Character=\"{0}\"" + ); + throw new ParseException(loc(r), msg, (char)qc); + } + final boolean isQuoted = (qc == '\'' || qc == '"'); + String s = null; + boolean isInEscape = false; + int c = 0; + while (c != -1) { + c = r.read(); + // Strict syntax requires that all control characters be escaped. + if (isStrict() && c <= 0x1F) + throw new ParseException("Unescaped control character encountered: ''0x{0}''", String.format("%04X", c)); + if (isInEscape) { + switch (c) { + case 'n': r.replace('\n'); break; + case 'r': r.replace('\r'); break; + case 't': r.replace('\t'); break; + case 'f': r.replace('\f'); break; + case 'b': r.replace('\b'); break; + case '\\': r.replace('\\'); break; + case '/': r.replace('/'); break; + case '\'': r.replace('\''); break; + case '"': r.replace('"'); break; + case 'u': { + String n = r.read(4); + try { + r.replace(Integer.parseInt(n, 16), 6); + } catch (NumberFormatException e) { + throw new ParseException(loc(r), "Invalid Unicode escape sequence in string."); + } + break; + } + default: + throw new ParseException(loc(r), "Invalid escape sequence in string."); + } + isInEscape = false; + } else { + if (c == '\\') { + isInEscape = true; + r.delete(); + } else if (isQuoted) { + if (c == qc) { + s = r.getMarked(1, -1); + break; + } + } else { + if (c == ',' || c == '}' || c == ']' || isWhitespace(c)) { + s = r.getMarked(0, -1); + r.unread(); + break; + } else if (c == -1) { + s = r.getMarked(0, 0); + break; + } + } + } + } + if (s == null) + throw new ParseException(loc(r), "Could not find expected end character ''{0}''.", (char)qc); + + // Look for concatenated string (i.e. whitespace followed by +). + skipCommentsAndSpace(r); + if (r.peek() == '+') { + if (isStrict()) + throw new ParseException(loc(r), "String concatenation detected."); + r.read(); // Skip past '+' + skipCommentsAndSpace(r); + s += parseString(r); + } + return trim(s); // End of input reached. + } + + /* + * Looks for the keywords true, false, or null. + * Throws an exception if any of these keywords are not found at the specified position. + */ + private void parseKeyword(String keyword, ParserReader r) throws Exception { + try { + String s = r.read(keyword.length()); + if (s.equals(keyword)) + return; + throw new ParseException(loc(r), "Unrecognized syntax."); + } catch (IndexOutOfBoundsException e) { + throw new ParseException(loc(r), "Unrecognized syntax."); + } + } + + /* + * Doesn't actually parse anything, but moves the position beyond any whitespace or comments. + * If positionOnNext is 'true', then the cursor will be set to the point immediately after + * the comments and whitespace. Otherwise, the cursor will be set to the last position of + * the comments and whitespace. + */ + private void skipCommentsAndSpace(ParserReader r) throws Exception { + int c = 0; + while ((c = r.read()) != -1) { + if (! isWhitespace(c)) { + if (c == '/') { + if (isStrict()) + throw new ParseException(loc(r), "Javascript comment detected."); + skipComments(r); + } else { + r.unread(); + return; + } + } + } + } + + /* + * Doesn't actually parse anything, but when positioned at the beginning of comment, + * it will move the pointer to the last character in the comment. + */ + private void skipComments(ParserReader r) throws ParseException, IOException { + int c = r.read(); + // "/* */" style comments + if (c == '*') { + while (c != -1) + if ((c = r.read()) == '*') + if ((c = r.read()) == '/') + return; + // "//" style comments + } else if (c == '/') { + while (c != -1) { + c = r.read(); + if (c == -1 || c == '\n') + return; + } + } + throw new ParseException(loc(r), "Open ended comment."); + } + + /* + * Call this method after you've finished a parsing a string to make sure that if there's any + * remainder in the input, that it consists only of whitespace and comments. + */ + private void validateEnd(ParserReader r) throws Exception { + skipCommentsAndSpace(r); + int c = r.read(); + if (c != -1 && c != ';') // var x = {...}; expressions can end with a semicolon. + throw new ParseException(loc(r), "Remainder after parse: ''{0}''.", (char)c); + } + + private ObjectMap loc(ParserReader r) { + return getLastLocation().append("line", r.getLine()).append("column", r.getColumn()); + } +}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/ab8f0faa/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlSerializer.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlSerializer.java new file mode 100644 index 0000000..c8598b5 --- /dev/null +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlSerializer.java @@ -0,0 +1,146 @@ +// *************************************************************************************************************************** +// * 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.juneau.yaml.proto; + +import java.util.*; + +import org.apache.juneau.*; +import org.apache.juneau.serializer.*; + +/** + * Serializes POJO models to JSON. + * + * <h5 class='section'>Media types:</h5> + * + * Handles <code>Accept</code> types: <code>application/json, text/json</code> + * <p> + * Produces <code>Content-Type</code> types: <code>application/json</code> + * + * <h5 class='section'>Description:</h5> + * + * The conversion is as follows... + * <ul class='spaced-list'> + * <li> + * Maps (e.g. {@link HashMap HashMaps}, {@link TreeMap TreeMaps}) are converted to JSON objects. + * <li> + * Collections (e.g. {@link HashSet HashSets}, {@link LinkedList LinkedLists}) and Java arrays are converted to + * JSON arrays. + * <li> + * {@link String Strings} are converted to JSON strings. + * <li> + * {@link Number Numbers} (e.g. {@link Integer}, {@link Long}, {@link Double}) are converted to JSON numbers. + * <li> + * {@link Boolean Booleans} are converted to JSON booleans. + * <li> + * {@code nulls} are converted to JSON nulls. + * <li> + * {@code arrays} are converted to JSON arrays. + * <li> + * {@code beans} are converted to JSON objects. + * </ul> + * + * <p> + * The types above are considered "JSON-primitive" object types. + * Any non-JSON-primitive object types are transformed into JSON-primitive object types through + * {@link org.apache.juneau.transform.PojoSwap PojoSwaps} associated through the + * {@link CoreObjectBuilder#pojoSwaps(Class...)} method. + * Several default transforms are provided for transforming Dates, Enums, Iterators, etc... + * + * <p> + * This serializer provides several serialization options. + * Typically, one of the predefined DEFAULT serializers will be sufficient. + * However, custom serializers can be constructed to fine-tune behavior. + * + * <h5 class='section'>Configurable properties:</h5> + * + * This class has the following properties associated with it: + * <ul> + * <li>{@link YamlSerializerContext} + * <li>{@link SerializerContext} + * <li>{@link BeanContext} + * </ul> + * + * <h5 class='section'>Example:</h5> + * <p class='bcode'> + * <jc>// Use one of the default serializers to serialize a POJO</jc> + * String json = JsonSerializer.<jsf>DEFAULT</jsf>.serialize(someObject); + * + * <jc>// Create a custom serializer for lax syntax using single quote characters</jc> + * JsonSerializer serializer = <jk>new</jk> JsonSerializerBuilder().simple().sq().build(); + * + * <jc>// Clone an existing serializer and modify it to use single-quotes</jc> + * JsonSerializer serializer = JsonSerializer.<jsf>DEFAULT</jsf>.builder().sq().build(); + * + * <jc>// Serialize a POJO to JSON</jc> + * String json = serializer.serialize(someObject); + * </p> + */ +public class YamlSerializer extends WriterSerializer { + + /** Default serializer, all default settings.*/ + public static final YamlSerializer DEFAULT = new YamlSerializer(PropertyStore.create()); + + + final YamlSerializerContext ctx; + + /** + * Constructor. + * + * @param propertyStore + * The property store containing all the settings for this object. + */ + public YamlSerializer(PropertyStore propertyStore) { + this(propertyStore, "application/yaml", "application/yaml", "application/yaml+*", "text/yaml", "text/yaml+*"); + } + + /** + * Constructor. + * + * @param propertyStore + * The property store containing all the settings for this object. + * @param produces + * The media type that this serializer produces. + * @param accept + * The accept media types that the serializer can handle. + * <p> + * Can contain meta-characters per the <code>media-type</code> specification of + * <a class="doclink" href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1">RFC2616/14.1</a> + * <p> + * If empty, then assumes the only media type supported is <code>produces</code>. + * <p> + * For example, if this serializer produces <js>"application/json"</js> but should handle media types of + * <js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be: + * <br><code><jk>super</jk>(propertyStore, <js>"application/json"</js>, <js>"application/json"</js>, <js>"text/json"</js>);</code> + * <br>...or... + * <br><code><jk>super</jk>(propertyStore, <js>"application/json"</js>, <js>"*​/json"</js>);</code> + */ + public YamlSerializer(PropertyStore propertyStore, String produces, String...accept) { + super(propertyStore, produces, accept); + this.ctx = createContext(YamlSerializerContext.class); + } + + @Override /* CoreObject */ + public YamlSerializerBuilder builder() { + return new YamlSerializerBuilder(propertyStore); + } + + + //-------------------------------------------------------------------------------- + // Entry point methods + //-------------------------------------------------------------------------------- + + @Override /* Serializer */ + public WriterSerializerSession createSession(SerializerSessionArgs args) { + return new YamlSerializerSession(ctx, args); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/ab8f0faa/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlSerializerBuilder.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlSerializerBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlSerializerBuilder.java new file mode 100644 index 0000000..69bdcb4 --- /dev/null +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlSerializerBuilder.java @@ -0,0 +1,658 @@ +// *************************************************************************************************************************** +// * 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.juneau.yaml.proto; + +import static org.apache.juneau.json.JsonSerializerContext.*; + +import java.util.*; + +import org.apache.juneau.*; +import org.apache.juneau.http.*; +import org.apache.juneau.serializer.*; + +/** + * Builder class for building instances of JSON serializers. + */ +public class YamlSerializerBuilder extends SerializerBuilder { + + /** + * Constructor, default settings. + */ + public YamlSerializerBuilder() { + super(); + } + + /** + * Constructor. + * + * @param propertyStore The initial configuration settings for this builder. + */ + public YamlSerializerBuilder(PropertyStore propertyStore) { + super(propertyStore); + } + + @Override /* CoreObjectBuilder */ + public YamlSerializer build() { + return new YamlSerializer(propertyStore); + } + + + //-------------------------------------------------------------------------------- + // Properties + //-------------------------------------------------------------------------------- + + /** + * <b>Configuration property:</b> Simple JSON mode. + * + * <ul> + * <li><b>Name:</b> <js>"JsonSerializer.simpleMode"</js> + * <li><b>Data type:</b> <code>Boolean</code> + * <li><b>Default:</b> <jk>false</jk> + * <li><b>Session-overridable:</b> <jk>true</jk> + * </ul> + * + * <p> + * If <jk>true</jk>, JSON attribute names will only be quoted when necessary. + * Otherwise, they are always quoted. + * + * <h5 class='section'>Notes:</h5> + * <ul> + * <li>This is equivalent to calling <code>property(<jsf>JSON_simpleMode</jsf>, value)</code>. + * </ul> + * + * @param value The new value for this property. + * @return This object (for method chaining). + * @see YamlSerializerContext#JSON_simpleMode + */ + public YamlSerializerBuilder simple(boolean value) { + return property(JSON_simpleMode, value); + } + + /** + * Shortcut for calling <code>setSimpleMode(<jk>true</jk>).sq()</code>. + * + * @return This object (for method chaining). + */ + public YamlSerializerBuilder simple() { + return simple(true).sq(); + } + + /** + * <b>Configuration property:</b> Prefix solidus <js>'/'</js> characters with escapes. + * + * <ul> + * <li><b>Name:</b> <js>"JsonSerializer.escapeSolidus"</js> + * <li><b>Data type:</b> <code>Boolean</code> + * <li><b>Default:</b> <jk>false</jk> + * <li><b>Session-overridable:</b> <jk>true</jk> + * </ul> + * + * <p> + * If <jk>true</jk>, solidus (e.g. slash) characters should be escaped. + * The JSON specification allows for either format. + * However, if you're embedding JSON in an HTML script tag, this setting prevents confusion when trying to + * serialize <xt><\/script></xt>. + * + * <h5 class='section'>Notes:</h5> + * <ul> + * <li>This is equivalent to calling <code>property(<jsf>JSON_escapeSolidus</jsf>, value)</code>. + * </ul> + * + * @param value The new value for this property. + * @return This object (for method chaining). + * @see YamlSerializerContext#JSON_escapeSolidus + */ + public YamlSerializerBuilder escapeSolidus(boolean value) { + return property(JSON_escapeSolidus, value); + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder maxDepth(int value) { + super.maxDepth(value); + return this; + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder initialDepth(int value) { + super.initialDepth(value); + return this; + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder detectRecursions(boolean value) { + super.detectRecursions(value); + return this; + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder ignoreRecursions(boolean value) { + super.ignoreRecursions(value); + return this; + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder useWhitespace(boolean value) { + super.useWhitespace(value); + return this; + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder ws() { + super.ws(); + return this; + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder maxIndent(int value) { + super.maxIndent(value); + return this; + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder addBeanTypeProperties(boolean value) { + super.addBeanTypeProperties(value); + return this; + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder quoteChar(char value) { + super.quoteChar(value); + return this; + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder sq() { + super.sq(); + return this; + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder trimNullProperties(boolean value) { + super.trimNullProperties(value); + return this; + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder trimEmptyCollections(boolean value) { + super.trimEmptyCollections(value); + return this; + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder trimEmptyMaps(boolean value) { + super.trimEmptyMaps(value); + return this; + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder trimStrings(boolean value) { + super.trimStrings(value); + return this; + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder uriContext(UriContext value) { + super.uriContext(value); + return this; + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder uriResolution(UriResolution value) { + super.uriResolution(value); + return this; + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder uriRelativity(UriRelativity value) { + super.uriRelativity(value); + return this; + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder sortCollections(boolean value) { + super.sortCollections(value); + return this; + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder sortMaps(boolean value) { + super.sortMaps(value); + return this; + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder abridged(boolean value) { + super.abridged(value); + return this; + } + + @Override /* SerializerBuilder */ + public YamlSerializerBuilder listener(Class<? extends SerializerListener> value) { + super.listener(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder beansRequireDefaultConstructor(boolean value) { + super.beansRequireDefaultConstructor(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder beansRequireSerializable(boolean value) { + super.beansRequireSerializable(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder beansRequireSettersForGetters(boolean value) { + super.beansRequireSettersForGetters(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder beansRequireSomeProperties(boolean value) { + super.beansRequireSomeProperties(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder beanMapPutReturnsOldValue(boolean value) { + super.beanMapPutReturnsOldValue(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder beanConstructorVisibility(Visibility value) { + super.beanConstructorVisibility(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder beanClassVisibility(Visibility value) { + super.beanClassVisibility(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder beanFieldVisibility(Visibility value) { + super.beanFieldVisibility(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder methodVisibility(Visibility value) { + super.methodVisibility(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder useJavaBeanIntrospector(boolean value) { + super.useJavaBeanIntrospector(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder useInterfaceProxies(boolean value) { + super.useInterfaceProxies(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder ignoreUnknownBeanProperties(boolean value) { + super.ignoreUnknownBeanProperties(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder ignoreUnknownNullBeanProperties(boolean value) { + super.ignoreUnknownNullBeanProperties(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder ignorePropertiesWithoutSetters(boolean value) { + super.ignorePropertiesWithoutSetters(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder ignoreInvocationExceptionsOnGetters(boolean value) { + super.ignoreInvocationExceptionsOnGetters(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder ignoreInvocationExceptionsOnSetters(boolean value) { + super.ignoreInvocationExceptionsOnSetters(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder sortProperties(boolean value) { + super.sortProperties(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder notBeanPackages(String...values) { + super.notBeanPackages(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder notBeanPackages(Collection<String> values) { + super.notBeanPackages(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder setNotBeanPackages(String...values) { + super.setNotBeanPackages(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder setNotBeanPackages(Collection<String> values) { + super.setNotBeanPackages(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder removeNotBeanPackages(String...values) { + super.removeNotBeanPackages(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder removeNotBeanPackages(Collection<String> values) { + super.removeNotBeanPackages(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder notBeanClasses(Class<?>...values) { + super.notBeanClasses(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder notBeanClasses(Collection<Class<?>> values) { + super.notBeanClasses(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder setNotBeanClasses(Class<?>...values) { + super.setNotBeanClasses(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder setNotBeanClasses(Collection<Class<?>> values) { + super.setNotBeanClasses(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder removeNotBeanClasses(Class<?>...values) { + super.removeNotBeanClasses(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder removeNotBeanClasses(Collection<Class<?>> values) { + super.removeNotBeanClasses(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder beanFilters(Class<?>...values) { + super.beanFilters(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder beanFilters(Collection<Class<?>> values) { + super.beanFilters(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder setBeanFilters(Class<?>...values) { + super.setBeanFilters(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder setBeanFilters(Collection<Class<?>> values) { + super.setBeanFilters(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder removeBeanFilters(Class<?>...values) { + super.removeBeanFilters(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder removeBeanFilters(Collection<Class<?>> values) { + super.removeBeanFilters(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder pojoSwaps(Class<?>...values) { + super.pojoSwaps(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder pojoSwaps(Collection<Class<?>> values) { + super.pojoSwaps(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder setPojoSwaps(Class<?>...values) { + super.setPojoSwaps(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder setPojoSwaps(Collection<Class<?>> values) { + super.setPojoSwaps(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder removePojoSwaps(Class<?>...values) { + super.removePojoSwaps(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder removePojoSwaps(Collection<Class<?>> values) { + super.removePojoSwaps(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder implClasses(Map<Class<?>,Class<?>> values) { + super.implClasses(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public <T> YamlSerializerBuilder implClass(Class<T> interfaceClass, Class<? extends T> implClass) { + super.implClass(interfaceClass, implClass); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder includeProperties(Map<String,String> values) { + super.includeProperties(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder includeProperties(String beanClassName, String properties) { + super.includeProperties(beanClassName, properties); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder includeProperties(Class<?> beanClass, String properties) { + super.includeProperties(beanClass, properties); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder excludeProperties(Map<String,String> values) { + super.excludeProperties(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder excludeProperties(String beanClassName, String properties) { + super.excludeProperties(beanClassName, properties); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder excludeProperties(Class<?> beanClass, String properties) { + super.excludeProperties(beanClass, properties); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder beanDictionary(Class<?>...values) { + super.beanDictionary(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder beanDictionary(Collection<Class<?>> values) { + super.beanDictionary(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder setBeanDictionary(Class<?>...values) { + super.setBeanDictionary(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder setBeanDictionary(Collection<Class<?>> values) { + super.setBeanDictionary(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder removeFromBeanDictionary(Class<?>...values) { + super.removeFromBeanDictionary(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder removeFromBeanDictionary(Collection<Class<?>> values) { + super.removeFromBeanDictionary(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder beanTypePropertyName(String value) { + super.beanTypePropertyName(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder defaultParser(Class<?> value) { + super.defaultParser(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder locale(Locale value) { + super.locale(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder timeZone(TimeZone value) { + super.timeZone(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder mediaType(MediaType value) { + super.mediaType(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder debug() { + super.debug(); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder property(String name, Object value) { + super.property(name, value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder properties(Map<String,Object> properties) { + super.properties(properties); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder addToProperty(String name, Object value) { + super.addToProperty(name, value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder putToProperty(String name, Object key, Object value) { + super.putToProperty(name, key, value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder putToProperty(String name, Object value) { + super.putToProperty(name, value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder removeFromProperty(String name, Object value) { + super.removeFromProperty(name, value); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder classLoader(ClassLoader classLoader) { + super.classLoader(classLoader); + return this; + } + + @Override /* CoreObjectBuilder */ + public YamlSerializerBuilder apply(PropertyStore copyFrom) { + super.apply(copyFrom); + return this; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/ab8f0faa/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlSerializerContext.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlSerializerContext.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlSerializerContext.java new file mode 100644 index 0000000..5714d42 --- /dev/null +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlSerializerContext.java @@ -0,0 +1,130 @@ +// *************************************************************************************************************************** +// * 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.juneau.yaml.proto; + +import org.apache.juneau.*; +import org.apache.juneau.serializer.*; + +/** + * Configurable properties on the {@link YamlSerializer} class. + * + * <p> + * Context properties are set by calling {@link PropertyStore#setProperty(String, Object)} on the property store + * passed into the constructor. + * + * <p> + * See {@link PropertyStore} for more information about context properties. + * + * <h6 class='topic'>Inherited configurable properties</h6> + * <ul class='doctree'> + * <li class='jc'> + * <a class="doclink" href="../BeanContext.html#ConfigProperties">BeanContext</a> + * - Properties associated with handling beans on serializers and parsers. + * <ul> + * <li class='jc'> + * <a class="doclink" href="../serializer/SerializerContext.html#ConfigProperties">SerializerContext</a> + * - Configurable properties common to all serializers. + * </ul> + * </li> + * </ul> + */ +public final class YamlSerializerContext extends SerializerContext { + + /** + * <b>Configuration property:</b> Simple JSON mode. + * + * <ul> + * <li><b>Name:</b> <js>"JsonSerializer.simpleMode"</js> + * <li><b>Data type:</b> <code>Boolean</code> + * <li><b>Default:</b> <jk>false</jk> + * <li><b>Session-overridable:</b> <jk>true</jk> + * </ul> + * + * <p> + * If <jk>true</jk>, JSON attribute names will only be quoted when necessary. + * Otherwise, they are always quoted. + */ + public static final String JSON_simpleMode = "JsonSerializer.simpleMode"; + + /** + * <b>Configuration property:</b> Prefix solidus <js>'/'</js> characters with escapes. + * + * <ul> + * <li><b>Name:</b> <js>"JsonSerializer.escapeSolidus"</js> + * <li><b>Data type:</b> <code>Boolean</code> + * <li><b>Default:</b> <jk>false</jk> + * <li><b>Session-overridable:</b> <jk>true</jk> + * </ul> + * + * <p> + * If <jk>true</jk>, solidus (e.g. slash) characters should be escaped. + * The JSON specification allows for either format. + * However, if you're embedding JSON in an HTML script tag, this setting prevents confusion when trying to serialize + * <xt><\/script></xt>. + */ + public static final String JSON_escapeSolidus = "JsonSerializer.escapeSolidus"; + + /** + * <b>Configuration property:</b> Add <js>"_type"</js> properties when needed. + * + * <ul> + * <li><b>Name:</b> <js>"JsonSerializer.addBeanTypeProperties"</js> + * <li><b>Data type:</b> <code>Boolean</code> + * <li><b>Default:</b> <jk>false</jk> + * <li><b>Session-overridable:</b> <jk>true</jk> + * </ul> + * + * <p> + * If <jk>true</jk>, then <js>"_type"</js> properties will be added to beans if their type cannot be inferred + * through reflection. + * This is used to recreate the correct objects during parsing if the object types cannot be inferred. + * For example, when serializing a {@code Map<String,Object>} field, where the bean class cannot be determined from + * the value type. + * + * <p> + * When present, this value overrides the {@link SerializerContext#SERIALIZER_addBeanTypeProperties} setting and is + * provided to customize the behavior of specific serializers in a {@link SerializerGroup}. + */ + public static final String JSON_addBeanTypeProperties = "JsonSerializer.addBeanTypeProperties"; + + final boolean + simpleMode, + escapeSolidus, + addBeanTypeProperties; + + /** + * Constructor. + * + * <p> + * Typically only called from {@link PropertyStore#getContext(Class)}. + * + * @param ps The property store that created this context. + */ + public YamlSerializerContext(PropertyStore ps) { + super(ps); + simpleMode = ps.getProperty(JSON_simpleMode, boolean.class, false); + escapeSolidus = ps.getProperty(JSON_escapeSolidus, boolean.class, false); + addBeanTypeProperties = ps.getProperty(JSON_addBeanTypeProperties, boolean.class, + ps.getProperty(SERIALIZER_addBeanTypeProperties, boolean.class, true)); + } + + @Override /* Context */ + public ObjectMap asMap() { + return super.asMap() + .append("JsonSerializerContext", new ObjectMap() + .append("simpleMode", simpleMode) + .append("escapeSolidus", escapeSolidus) + .append("addBeanTypeProperties", addBeanTypeProperties) + ); + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/ab8f0faa/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlSerializerSession.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlSerializerSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlSerializerSession.java new file mode 100644 index 0000000..1f252c9 --- /dev/null +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlSerializerSession.java @@ -0,0 +1,244 @@ +// *************************************************************************************************************************** +// * 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.juneau.yaml.proto; + +import static org.apache.juneau.json.JsonSerializerContext.*; + +import java.util.*; + +import org.apache.juneau.*; +import org.apache.juneau.internal.*; +import org.apache.juneau.serializer.*; +import org.apache.juneau.transform.*; + +/** + * Session object that lives for the duration of a single use of {@link YamlSerializer}. + * + * <p> + * This class is NOT thread safe. + * It is typically discarded after one-time use although it can be reused within the same thread. + */ +public class YamlSerializerSession extends WriterSerializerSession { + + private final boolean + addBeanTypeProperties; + + /** + * Create a new session using properties specified in the context. + * + * @param ctx + * The context creating this session object. + * The context contains all the configuration settings for this object. + * @param args + * Runtime arguments. + * These specify session-level information such as locale and URI context. + * It also include session-level properties that override the properties defined on the bean and + * serializer contexts. + */ + protected YamlSerializerSession(YamlSerializerContext ctx, SerializerSessionArgs args) { + super(ctx, args); + ObjectMap p = getProperties(); + if (p.isEmpty()) { + addBeanTypeProperties = ctx.addBeanTypeProperties; + } else { + addBeanTypeProperties = p.getBoolean(JSON_addBeanTypeProperties, ctx.addBeanTypeProperties); + } + } + + + @Override /* SerializerSesssion */ + protected void doSerialize(SerializerPipe out, Object o) throws Exception { + serializeAnything(getJsonWriter(out), o, getExpectedRootType(o), "root", null); + } + + /* + * Workhorse method. + * Determines the type of object, and then calls the appropriate type-specific serialization method. + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + SerializerWriter serializeAnything(YamlWriter out, Object o, ClassMeta<?> eType, String attrName, BeanPropertyMeta pMeta) throws Exception { + + if (o == null) { + out.append("~"); + return out; + } + + if (eType == null) + eType = object(); + + ClassMeta<?> aType; // The actual type + ClassMeta<?> sType; // The serialized type + + aType = push(attrName, o, eType); + boolean isRecursion = aType == null; + + // Handle recursion + if (aType == null) { + o = null; + aType = object(); + } + + sType = aType; + String typeName = getBeanTypeName(eType, aType, pMeta); + + // Swap if necessary + PojoSwap swap = aType.getPojoSwap(this); + if (swap != null) { + o = swap.swap(this, o); + sType = swap.getSwapClassMeta(this); + + // If the getSwapClass() method returns Object, we need to figure out + // the actual type now. + if (sType.isObject()) + sType = getClassMetaForObject(o); + } + + // '\0' characters are considered null. + if (o == null || (sType.isChar() && ((Character)o).charValue() == 0)) + out.append("~"); + else if (sType.isNumber() || sType.isBoolean()) + out.append(o); + else if (sType.isBean()) + serializeBeanMap(out, toBeanMap(o), typeName); + else if (sType.isUri() || (pMeta != null && pMeta.isUri())) + out.uriValue(o); + else if (sType.isMap()) { + if (o instanceof BeanMap) + serializeBeanMap(out, (BeanMap)o, typeName); + else + serializeMap(out, (Map)o, eType); + } + else if (sType.isCollection()) { + serializeCollection(out, (Collection) o, eType); + } + else if (sType.isArray()) { + serializeCollection(out, toList(sType.getInnerClass(), o), eType); + } + else if (sType.isReader() || sType.isInputStream()) { + IOUtils.pipe(o, out); + } + else + out.stringValue(toString(o)); + + if (! isRecursion) + pop(); + return out; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private SerializerWriter serializeMap(YamlWriter out, Map m, ClassMeta<?> type) throws Exception { + + ClassMeta<?> keyType = type.getKeyType(), valueType = type.getValueType(); + + m = sort(m); + + int i = indent; + + Iterator mapEntries = m.entrySet().iterator(); + + while (mapEntries.hasNext()) { + Map.Entry e = (Map.Entry) mapEntries.next(); + Object value = e.getValue(); + + Object key = generalize(e.getKey(), keyType); + + out.attr(toString(key)).append(':').s(); + + serializeAnything(out, value, valueType, (key == null ? null : toString(key)), null); + + if (mapEntries.hasNext()) + out.nl(i); + } + + out.cre(i-1); + + return out; + } + + private SerializerWriter serializeBeanMap(YamlWriter out, BeanMap<?> m, String typeName) throws Exception { + int i = indent; + out.append('{'); + + boolean addComma = false; + for (BeanPropertyValue p : m.getValues(isTrimNulls(), typeName != null ? createBeanTypeNameProperty(m, typeName) : null)) { + BeanPropertyMeta pMeta = p.getMeta(); + ClassMeta<?> cMeta = p.getClassMeta(); + String key = p.getName(); + Object value = p.getValue(); + Throwable t = p.getThrown(); + if (t != null) + onBeanGetterException(pMeta, t); + + if (canIgnoreValue(cMeta, key, value)) + continue; + + if (addComma) + out.append(',').smi(i); + + out.cr(i).attr(key).append(':').s(i); + + serializeAnything(out, value, cMeta, key, pMeta); + + addComma = true; + } + out.cre(i-1).append('}'); + return out; + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private SerializerWriter serializeCollection(YamlWriter out, Collection c, ClassMeta<?> type) throws Exception { + + ClassMeta<?> elementType = type.getElementType(); + + c = sort(c); + + out.append('['); + + for (Iterator i = c.iterator(); i.hasNext();) { + Object value = i.next(); + out.cr(indent); + serializeAnything(out, value, elementType, "<iterator>", null); + if (i.hasNext()) + out.append(',').smi(indent); + } + out.cre(indent-1).append(']'); + return out; + } + + + /** + * Returns the {@link YamlSerializerContext#JSON_addBeanTypeProperties} setting value for this session. + * + * @return The {@link YamlSerializerContext#JSON_addBeanTypeProperties} setting value for this session. + */ + @Override /* SerializerSession */ + protected final boolean isAddBeanTypeProperties() { + return addBeanTypeProperties; + } + + /** + * Converts the specified output target object to an {@link YamlWriter}. + * + * @param out The output target object. + * @return The output target object wrapped in an {@link YamlWriter}. + * @throws Exception + */ + protected final YamlWriter getJsonWriter(SerializerPipe out) throws Exception { + Object output = out.getRawOutput(); + if (output instanceof YamlWriter) + return (YamlWriter)output; + YamlWriter w = new YamlWriter(out.getWriter(), getQuoteChar(), isTrimStrings(), getUriResolver()); + out.setWriter(w); + return w; + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/ab8f0faa/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlWriter.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlWriter.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlWriter.java new file mode 100644 index 0000000..f9345b0 --- /dev/null +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlWriter.java @@ -0,0 +1,288 @@ +// *************************************************************************************************************************** +// * 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.juneau.yaml.proto; + +import java.io.*; + +import org.apache.juneau.*; +import org.apache.juneau.internal.*; +import org.apache.juneau.serializer.*; + +/** + * Specialized writer for serializing JSON. + * + * <h5 class='section'>Notes:</h5> + * <ul> + * <li>This class is not intended for external use. + * </ul> + */ +public final class YamlWriter extends SerializerWriter { + + // Characters that trigger special handling of serializing attribute values. + private static final AsciiSet + encodedChars = new AsciiSet("\n\t\b\f\r'\"\\"); + + private static final KeywordSet reservedWords = new KeywordSet( + "y","Y","yes","Yes","YES","n","N","no","No","NO", + "true","True","TRUE","false","False","FALSE", + "on","On","ON","off","Off","OFF" + ); + + + + // Characters that represent attribute name characters that don't trigger quoting. + // These are actually more strict than the actual Javascript specification, but + // can be narrowed in the future if necessary. + // For example, we quote attributes that start with $ even though we don't need to. + private static final AsciiSet validAttrChars = new AsciiSet("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"); + private static final AsciiSet validFirstAttrChars = new AsciiSet("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"); + + private final AsciiSet ec; + + /** + * Constructor. + * + * @param out The writer being wrapped. + * @param quoteChar The quote character to use (i.e. <js>'\''</js> or <js>'"'</js>) + * @param trimStrings If <jk>true</jk>, strings will be trimmed before being serialized. + * @param uriResolver The URI resolver for resolving URIs to absolute or root-relative form. + */ + protected YamlWriter(Writer out, char quoteChar, boolean trimStrings, UriResolver uriResolver) { + super(out, true, Integer.MAX_VALUE, trimStrings, quoteChar, uriResolver); + this.ec = encodedChars; + } + + /** + * Serializes the specified object as a JSON string value. + * + * @param s The object being serialized. + * @return This object (for method chaining). + * @throws IOException Should never happen. + */ + public YamlWriter stringValue(String s) throws IOException { + if (s == null) + return this; + boolean doConvert = false; + for (int i = 0; i < s.length() && ! doConvert; i++) { + char c = s.charAt(i); + doConvert |= ec.contains(c); + } + q(); + if (! doConvert) { + out.append(s); + } else { + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (ec.contains(c)) { + if (c == '\n') + out.append('\\').append('n'); + else if (c == '\t') + out.append('\\').append('t'); + else if (c == '\b') + out.append('\\').append('b'); + else if (c == '\f') + out.append('\\').append('f'); + else if (c == quoteChar) + out.append('\\').append(quoteChar); + else if (c == '\\') + out.append('\\').append('\\'); + else if (c != '\r') + out.append(c); + } else { + out.append(c); + } + } + } + q(); + return this; + } + + /** + * Serializes the specified object as a JSON attribute name. + * + * @param s The object being serialized. + * @return This object (for method chaining). + * @throws IOException Should never happen. + */ + public YamlWriter attr(String s) throws IOException { + /* + * Converts a Java string to an acceptable JSON attribute name. If + * useStrictJson is false, then quotes will only be used if the attribute + * name consists of only alphanumeric characters. + */ + boolean doConvert = false; // Always convert when not in lax mode. + + // If the attribute is null, it must always be printed as null without quotes. + // Technically, this isn't part of the JSON spec, but it does allow for null key values. + if (s == null) { + s = "~"; + doConvert = false; + + } else { + + // Look for characters that would require the attribute to be quoted. + // All possible numbers should be caught here. + if (! doConvert) { + for (int i = 0; i < s.length() && ! doConvert; i++) { + char c = s.charAt(i); + doConvert |= ! (i == 0 ? validFirstAttrChars.contains(c) : validAttrChars.contains(c)); + } + } + + // Reserved words and blanks must be quoted. + if (! doConvert) { + if (s.isEmpty() || reservedWords.contains(s)) + doConvert = true; + } + } + + // If no conversion necessary, just print the attribute as-is. + if (doConvert) + stringValue(s); + else + out.append(s); + + return this; + } + + /** + * Appends a URI to the output. + * + * @param uri The URI to append to the output. + * @return This object (for method chaining). + * @throws IOException + */ + public SerializerWriter uriValue(Object uri) throws IOException { + return stringValue(uriResolver.resolve(uri)); + } + + //-------------------------------------------------------------------------------- + // Overridden methods + //-------------------------------------------------------------------------------- + + @Override /* SerializerWriter */ + public YamlWriter cr(int depth) throws IOException { + super.cr(depth); + return this; + } + + @Override /* SerializerWriter */ + public YamlWriter cre(int depth) throws IOException { + super.cre(depth); + return this; + } + + /** + * Performs an indentation only if we're currently past max indentation. + * + * @param depth The current indentation depth. + * @return This object (for method chaining). + * @throws IOException + */ + public YamlWriter smi(int depth) throws IOException { + if (depth > maxIndent) + super.s(); + return this; + } + + @Override /* SerializerWriter */ + public YamlWriter appendln(int indent, String text) throws IOException { + super.appendln(indent, text); + return this; + } + + @Override /* SerializerWriter */ + public YamlWriter appendln(String text) throws IOException { + super.appendln(text); + return this; + } + + @Override /* SerializerWriter */ + public YamlWriter append(int indent, String text) throws IOException { + super.append(indent, text); + return this; + } + + @Override /* SerializerWriter */ + public YamlWriter append(int indent, char c) throws IOException { + super.append(indent, c); + return this; + } + + @Override /* SerializerWriter */ + public YamlWriter s() throws IOException { + super.s(); + return this; + } + + /** + * Adds a space only if the current indentation level is below maxIndent. + * + * @param indent + * @return This object (for method chaining). + * @throws IOException + */ + public YamlWriter s(int indent) throws IOException { + if (indent <= maxIndent) + super.s(); + return this; + } + + @Override /* SerializerWriter */ + public YamlWriter q() throws IOException { + super.q(); + return this; + } + + @Override /* SerializerWriter */ + public YamlWriter i(int indent) throws IOException { + super.i(indent); + return this; + } + + @Override /* SerializerWriter */ + public YamlWriter nl(int indent) throws IOException { + super.nl(indent); + return this; + } + + @Override /* SerializerWriter */ + public YamlWriter append(Object text) throws IOException { + super.append(text); + return this; + } + + @Override /* SerializerWriter */ + public YamlWriter append(String text) throws IOException { + super.append(text); + return this; + } + + @Override /* SerializerWriter */ + public YamlWriter appendIf(boolean b, String text) throws IOException { + super.appendIf(b, text); + return this; + } + + @Override /* SerializerWriter */ + public YamlWriter appendIf(boolean b, char c) throws IOException { + super.appendIf(b, c); + return this; + } + + @Override /* SerializerWriter */ + public YamlWriter append(char c) throws IOException { + super.append(c); + return this; + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/ab8f0faa/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/annotation/Yaml.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/annotation/Yaml.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/annotation/Yaml.java new file mode 100644 index 0000000..08e2e50 --- /dev/null +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/annotation/Yaml.java @@ -0,0 +1,36 @@ +// *************************************************************************************************************************** +// * 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.juneau.yaml.proto.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +/** + * Annotation for specifying various YAML options for the YAML serializers and parsers. + * + * <p> + * Can be applied to Java types. + * + * <p> + * Can be used for the following: + * <ul class='spaced-list'> + * </ul> + */ +@Documented +@Target({TYPE}) +@Retention(RUNTIME) +@Inherited +public @interface Yaml { +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/ab8f0faa/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/annotation/package.html ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/annotation/package.html b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/annotation/package.html new file mode 100644 index 0000000..df41b35 --- /dev/null +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/annotation/package.html @@ -0,0 +1,41 @@ +<!DOCTYPE HTML> +<!-- +/*************************************************************************************************************************** + * 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> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <style type="text/css"> + /* For viewing in Page Designer */ + @IMPORT url("../../../../../../../javadoc.css"); + + /* For viewing in REST interface */ + @IMPORT url("../htdocs/javadoc.css"); + body { + margin: 20px; + } + </style> + <script> + /* Replace all @code and @link tags. */ + window.onload = function() { + document.body.innerHTML = document.body.innerHTML.replace(/\{\@code ([^\}]+)\}/g, '<code>$1</code>'); + document.body.innerHTML = document.body.innerHTML.replace(/\{\@link (([^\}]+)\.)?([^\.\}]+)\}/g, '<code>$3</code>'); + } + </script> +</head> +<body> +<p>JSON annotations</p> +</body> +</html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/ab8f0faa/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/doc-files/Example_HTML.png ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/doc-files/Example_HTML.png b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/doc-files/Example_HTML.png new file mode 100644 index 0000000..b4a3576 Binary files /dev/null and b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/doc-files/Example_HTML.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/ab8f0faa/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/doc-files/Example_JSON.png ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/doc-files/Example_JSON.png b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/doc-files/Example_JSON.png new file mode 100644 index 0000000..13b5c22 Binary files /dev/null and b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/doc-files/Example_JSON.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/ab8f0faa/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/doc-files/Example_JSONSchema.png ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/doc-files/Example_JSONSchema.png b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/doc-files/Example_JSONSchema.png new file mode 100644 index 0000000..bf1cdc6 Binary files /dev/null and b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/doc-files/Example_JSONSchema.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/ab8f0faa/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/doc-files/Example_JSONSimple.png ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/doc-files/Example_JSONSimple.png b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/doc-files/Example_JSONSimple.png new file mode 100644 index 0000000..935e8a9 Binary files /dev/null and b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/doc-files/Example_JSONSimple.png differ
