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.util.*; 018 019import org.apache.juneau.*; 020import org.apache.juneau.parser.*; 021import org.apache.juneau.transform.*; 022 023/** 024 * Session object that lives for the duration of a single use of {@link MsgPackParser}. 025 * 026 * <p> 027 * This class is NOT thread safe. 028 * It is typically discarded after one-time use although it can be reused against multiple inputs. 029 */ 030@SuppressWarnings({ "rawtypes", "unchecked" }) 031public final class MsgPackParserSession extends InputStreamParserSession { 032 033 /** 034 * Create a new session using properties specified in the context. 035 * 036 * @param ctx 037 * The context creating this session object. 038 * The context contains all the configuration settings for this object. 039 * @param args 040 * Runtime session arguments. 041 */ 042 protected MsgPackParserSession(MsgPackParser ctx, ParserSessionArgs args) { 043 super(ctx, args); 044 } 045 046 @Override /* ParserSession */ 047 protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws Exception { 048 try (MsgPackInputStream is = new MsgPackInputStream(pipe)) { 049 return parseAnything(type, is, getOuter(), null); 050 } 051 } 052 053 /* 054 * Workhorse method. 055 */ 056 private <T> T parseAnything(ClassMeta<?> eType, MsgPackInputStream is, Object outer, BeanPropertyMeta pMeta) throws Exception { 057 058 if (eType == null) 059 eType = object(); 060 PojoSwap<T,Object> swap = (PojoSwap<T,Object>)eType.getPojoSwap(this); 061 BuilderSwap<T,Object> builder = (BuilderSwap<T,Object>)eType.getBuilderSwap(this); 062 ClassMeta<?> sType = null; 063 if (builder != null) 064 sType = builder.getBuilderClassMeta(this); 065 else if (swap != null) 066 sType = swap.getSwapClassMeta(this); 067 else 068 sType = eType; 069 setCurrentClass(sType); 070 071 Object o = null; 072 DataType dt = is.readDataType(); 073 int length = (int)is.readLength(); 074 075 if (dt != DataType.NULL) { 076 if (dt == BOOLEAN) 077 o = is.readBoolean(); 078 else if (dt == INT) 079 o = is.readInt(); 080 else if (dt == LONG) 081 o = is.readLong(); 082 else if (dt == FLOAT) 083 o = is.readFloat(); 084 else if (dt == DOUBLE) 085 o = is.readDouble(); 086 else if (dt == STRING) 087 o = trim(is.readString()); 088 else if (dt == BIN) 089 o = is.readBinary(); 090 else if (dt == ARRAY && sType.isObject()) { 091 ObjectList ol = new ObjectList(this); 092 for (int i = 0; i < length; i++) 093 ol.add(parseAnything(object(), is, outer, pMeta)); 094 o = ol; 095 } else if (dt == MAP && sType.isObject()) { 096 ObjectMap om = new ObjectMap(this); 097 for (int i = 0; i < length; i++) 098 om.put((String)parseAnything(string(), is, outer, pMeta), parseAnything(object(), is, om, pMeta)); 099 o = cast(om, pMeta, eType); 100 } 101 102 if (sType.isObject()) { 103 // Do nothing. 104 } else if (sType.isBoolean() || sType.isCharSequence() || sType.isChar() || sType.isNumber()) { 105 o = convertToType(o, sType); 106 } else if (sType.isMap()) { 107 if (dt == MAP) { 108 Map m = (sType.canCreateNewInstance(outer) ? (Map)sType.newInstance(outer) : new ObjectMap(this)); 109 for (int i = 0; i < length; i++) { 110 Object key = parseAnything(sType.getKeyType(), is, outer, pMeta); 111 ClassMeta<?> vt = sType.getValueType(); 112 Object value = parseAnything(vt, is, m, pMeta); 113 setName(vt, value, key); 114 m.put(key, value); 115 } 116 o = m; 117 } else { 118 throw new ParseException(loc(is), "Invalid data type {0} encountered for parse type {1}", dt, sType); 119 } 120 } else if (builder != null || sType.canCreateNewBean(outer)) { 121 if (dt == MAP) { 122 BeanMap m = builder == null ? newBeanMap(outer, sType.getInnerClass()) : toBeanMap(builder.create(this, eType)); 123 for (int i = 0; i < length; i++) { 124 String pName = parseAnything(string(), is, m.getBean(false), null); 125 BeanPropertyMeta bpm = m.getPropertyMeta(pName); 126 if (bpm == null) { 127 if (pName.equals(getBeanTypePropertyName(eType))) 128 parseAnything(string(), is, null, null); 129 else 130 onUnknownProperty(is.getPipe(), pName, m, 0, is.getPosition()); 131 } else { 132 ClassMeta<?> cm = bpm.getClassMeta(); 133 Object value = parseAnything(cm, is, m.getBean(false), bpm); 134 setName(cm, value, pName); 135 bpm.set(m, pName, value); 136 } 137 } 138 o = builder == null ? m.getBean() : builder.build(this, m.getBean(), eType); 139 } else { 140 throw new ParseException(loc(is), "Invalid data type {0} encountered for parse type {1}", dt, sType); 141 } 142 } else if (sType.canCreateNewInstanceFromString(outer) && dt == STRING) { 143 o = sType.newInstanceFromString(outer, o == null ? "" : o.toString()); 144 } else if (sType.canCreateNewInstanceFromNumber(outer) && dt.isOneOf(INT, LONG, FLOAT, DOUBLE)) { 145 o = sType.newInstanceFromNumber(this, outer, (Number)o); 146 } else if (sType.isCollection()) { 147 if (dt == MAP) { 148 ObjectMap m = new ObjectMap(this); 149 for (int i = 0; i < length; i++) 150 m.put((String)parseAnything(string(), is, outer, pMeta), parseAnything(object(), is, m, pMeta)); 151 o = cast(m, pMeta, eType); 152 } else if (dt == ARRAY) { 153 Collection l = ( 154 sType.canCreateNewInstance(outer) 155 ? (Collection)sType.newInstance() 156 : new ObjectList(this) 157 ); 158 for (int i = 0; i < length; i++) 159 l.add(parseAnything(sType.getElementType(), is, l, pMeta)); 160 o = l; 161 } else { 162 throw new ParseException(loc(is), "Invalid data type {0} encountered for parse type {1}", dt, sType); 163 } 164 } else if (sType.isArray() || sType.isArgs()) { 165 if (dt == MAP) { 166 ObjectMap m = new ObjectMap(this); 167 for (int i = 0; i < length; i++) 168 m.put((String)parseAnything(string(), is, outer, pMeta), parseAnything(object(), is, m, pMeta)); 169 o = cast(m, pMeta, eType); 170 } else if (dt == ARRAY) { 171 Collection l = ( 172 sType.isCollection() && sType.canCreateNewInstance(outer) 173 ? (Collection)sType.newInstance() 174 : new ObjectList(this) 175 ); 176 for (int i = 0; i < length; i++) 177 l.add(parseAnything(sType.isArgs() ? sType.getArg(i) : sType.getElementType(), is, l, pMeta)); 178 o = toArray(sType, l); 179 } else { 180 throw new ParseException(loc(is), "Invalid data type {0} encountered for parse type {1}", dt, sType); 181 } 182 } else if (dt == MAP) { 183 ObjectMap m = new ObjectMap(this); 184 for (int i = 0; i < length; i++) 185 m.put((String)parseAnything(string(), is, outer, pMeta), parseAnything(object(), is, m, pMeta)); 186 if (m.containsKey(getBeanTypePropertyName(eType))) 187 o = cast(m, pMeta, eType); 188 else 189 throw new ParseException(loc(is), "Class ''{0}'' could not be instantiated. Reason: ''{1}''", 190 sType.getInnerClass().getName(), sType.getNotABeanReason()); 191 } else { 192 throw new ParseException(loc(is), "Invalid data type {0} encountered for parse type {1}", dt, sType); 193 } 194 } 195 196 if (swap != null && o != null) 197 o = swap.unswap(this, o, eType); 198 199 if (outer != null) 200 setParent(eType, o, outer); 201 202 return (T)o; 203 } 204 205 private ObjectMap loc(MsgPackInputStream is) { 206 return getLastLocation().append("position", is.getPosition()); 207 } 208}