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