001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.msgpack; 014 015import static org.apache.juneau.msgpack.DataType.*; 016 017import java.io.IOException; 018import java.util.*; 019 020import org.apache.juneau.*; 021import org.apache.juneau.parser.*; 022import org.apache.juneau.transform.*; 023 024/** 025 * Session object that lives for the duration of a single use of {@link MsgPackParser}. 026 * 027 * <p> 028 * This class is NOT thread safe. 029 * It is typically discarded after one-time use although it can be reused against multiple inputs. 030 */ 031@SuppressWarnings({ "rawtypes", "unchecked" }) 032public final class MsgPackParserSession extends InputStreamParserSession { 033 034 /** 035 * Create a new session using properties specified in the context. 036 * 037 * @param ctx 038 * The context creating this session object. 039 * The context contains all the configuration settings for this object. 040 * @param args 041 * Runtime session arguments. 042 */ 043 protected MsgPackParserSession(MsgPackParser ctx, ParserSessionArgs args) { 044 super(ctx, args); 045 } 046 047 @Override /* ParserSession */ 048 protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws IOException, ParseException, ExecutableException { 049 try (MsgPackInputStream is = new MsgPackInputStream(pipe)) { 050 return parseAnything(type, is, getOuter(), null); 051 } 052 } 053 054 /* 055 * Workhorse method. 056 */ 057 private <T> T parseAnything(ClassMeta<?> eType, MsgPackInputStream is, Object outer, BeanPropertyMeta pMeta) throws IOException, ParseException, ExecutableException { 058 059 if (eType == null) 060 eType = object(); 061 PojoSwap<T,Object> swap = (PojoSwap<T,Object>)eType.getPojoSwap(this); 062 BuilderSwap<T,Object> builder = (BuilderSwap<T,Object>)eType.getBuilderSwap(this); 063 ClassMeta<?> sType = null; 064 if (builder != null) 065 sType = builder.getBuilderClassMeta(this); 066 else if (swap != null) 067 sType = swap.getSwapClassMeta(this); 068 else 069 sType = eType; 070 setCurrentClass(sType); 071 072 Object o = null; 073 DataType dt = is.readDataType(); 074 int length = (int)is.readLength(); 075 076 if (dt != DataType.NULL) { 077 if (dt == BOOLEAN) 078 o = is.readBoolean(); 079 else if (dt == INT) 080 o = is.readInt(); 081 else if (dt == LONG) 082 o = is.readLong(); 083 else if (dt == FLOAT) 084 o = is.readFloat(); 085 else if (dt == DOUBLE) 086 o = is.readDouble(); 087 else if (dt == STRING) 088 o = trim(is.readString()); 089 else if (dt == BIN) 090 o = is.readBinary(); 091 else if (dt == ARRAY && sType.isObject()) { 092 ObjectList ol = new ObjectList(this); 093 for (int i = 0; i < length; i++) 094 ol.add(parseAnything(object(), is, outer, pMeta)); 095 o = ol; 096 } else if (dt == MAP && sType.isObject()) { 097 ObjectMap om = new ObjectMap(this); 098 for (int i = 0; i < length; i++) 099 om.put((String)parseAnything(string(), is, outer, pMeta), parseAnything(object(), is, om, pMeta)); 100 o = cast(om, pMeta, eType); 101 } 102 103 if (sType.isObject()) { 104 // Do nothing. 105 } else if (sType.isBoolean() || sType.isCharSequence() || sType.isChar() || sType.isNumber()) { 106 o = convertToType(o, sType); 107 } else if (sType.isMap()) { 108 if (dt == MAP) { 109 Map m = (sType.canCreateNewInstance(outer) ? (Map)sType.newInstance(outer) : new ObjectMap(this)); 110 for (int i = 0; i < length; i++) { 111 Object key = parseAnything(sType.getKeyType(), is, outer, pMeta); 112 ClassMeta<?> vt = sType.getValueType(); 113 Object value = parseAnything(vt, is, m, pMeta); 114 setName(vt, value, key); 115 m.put(key, value); 116 } 117 o = m; 118 } else { 119 throw new ParseException(this, "Invalid data type {0} encountered for parse type {1}", dt, sType); 120 } 121 } else if (builder != null || sType.canCreateNewBean(outer)) { 122 if (dt == MAP) { 123 BeanMap m = builder == null ? newBeanMap(outer, sType.getInnerClass()) : toBeanMap(builder.create(this, eType)); 124 for (int i = 0; i < length; i++) { 125 String pName = parseAnything(string(), is, m.getBean(false), null); 126 BeanPropertyMeta bpm = m.getPropertyMeta(pName); 127 if (bpm == null) { 128 if (pName.equals(getBeanTypePropertyName(eType))) 129 parseAnything(string(), is, null, null); 130 else 131 onUnknownProperty(pName, m); 132 } else { 133 ClassMeta<?> cm = bpm.getClassMeta(); 134 Object value = parseAnything(cm, is, m.getBean(false), bpm); 135 setName(cm, value, pName); 136 bpm.set(m, pName, value); 137 } 138 } 139 o = builder == null ? m.getBean() : builder.build(this, m.getBean(), eType); 140 } else { 141 throw new ParseException(this, "Invalid data type {0} encountered for parse type {1}", dt, sType); 142 } 143 } else if (sType.canCreateNewInstanceFromString(outer) && dt == STRING) { 144 o = sType.newInstanceFromString(outer, o == null ? "" : o.toString()); 145 } else if (sType.isCollection()) { 146 if (dt == MAP) { 147 ObjectMap m = new ObjectMap(this); 148 for (int i = 0; i < length; i++) 149 m.put((String)parseAnything(string(), is, outer, pMeta), parseAnything(object(), is, m, pMeta)); 150 o = cast(m, pMeta, eType); 151 } else if (dt == ARRAY) { 152 Collection l = ( 153 sType.canCreateNewInstance(outer) 154 ? (Collection)sType.newInstance() 155 : new ObjectList(this) 156 ); 157 for (int i = 0; i < length; i++) 158 l.add(parseAnything(sType.getElementType(), is, l, pMeta)); 159 o = l; 160 } else { 161 throw new ParseException(this, "Invalid data type {0} encountered for parse type {1}", dt, sType); 162 } 163 } else if (sType.isArray() || sType.isArgs()) { 164 if (dt == MAP) { 165 ObjectMap m = new ObjectMap(this); 166 for (int i = 0; i < length; i++) 167 m.put((String)parseAnything(string(), is, outer, pMeta), parseAnything(object(), is, m, pMeta)); 168 o = cast(m, pMeta, eType); 169 } else if (dt == ARRAY) { 170 Collection l = ( 171 sType.isCollection() && sType.canCreateNewInstance(outer) 172 ? (Collection)sType.newInstance() 173 : new ObjectList(this) 174 ); 175 for (int i = 0; i < length; i++) 176 l.add(parseAnything(sType.isArgs() ? sType.getArg(i) : sType.getElementType(), is, l, pMeta)); 177 o = toArray(sType, l); 178 } else { 179 throw new ParseException(this, "Invalid data type {0} encountered for parse type {1}", dt, sType); 180 } 181 } else if (dt == MAP) { 182 ObjectMap m = new ObjectMap(this); 183 for (int i = 0; i < length; i++) 184 m.put((String)parseAnything(string(), is, outer, pMeta), parseAnything(object(), is, m, pMeta)); 185 if (m.containsKey(getBeanTypePropertyName(eType))) 186 o = cast(m, pMeta, eType); 187 else 188 throw new ParseException(this, "Class ''{0}'' could not be instantiated. Reason: ''{1}''", 189 sType.getInnerClass().getName(), sType.getNotABeanReason()); 190 } else { 191 throw new ParseException(this, "Invalid data type {0} encountered for parse type {1}", dt, sType); 192 } 193 } 194 195 if (swap != null && o != null) 196 o = unswap(swap, o, eType); 197 198 if (outer != null) 199 setParent(eType, o, outer); 200 201 return (T)o; 202 } 203 204 //----------------------------------------------------------------------------------------------------------------- 205 // Other methods 206 //----------------------------------------------------------------------------------------------------------------- 207 208 @Override /* Session */ 209 public ObjectMap toMap() { 210 return super.toMap() 211 .append("MsgPackParserSession", new DefaultFilteringObjectMap() 212 ); 213 } 214}