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.internal.CollectionUtils.*; 016import static org.apache.juneau.msgpack.DataType.*; 017 018import java.io.IOException; 019import java.lang.reflect.*; 020import java.util.*; 021import java.util.function.*; 022 023import org.apache.juneau.*; 024import org.apache.juneau.collections.*; 025import org.apache.juneau.httppart.*; 026import org.apache.juneau.internal.*; 027import org.apache.juneau.parser.*; 028import org.apache.juneau.swap.*; 029 030/** 031 * Session object that lives for the duration of a single use of {@link MsgPackParser}. 032 * 033 * <h5 class='section'>Notes:</h5><ul> 034 * <li class='warn'>This class is not thread safe and is typically discarded after one use. 035 * </ul> 036 * 037 * <h5 class='section'>See Also:</h5><ul> 038 * <li class='link'><a class="doclink" href="../../../../index.html#jm.MsgPackDetails">MessagePack Details</a> 039 040 * </ul> 041 */ 042@SuppressWarnings({ "rawtypes", "unchecked" }) 043public final class MsgPackParserSession extends InputStreamParserSession { 044 045 //------------------------------------------------------------------------------------------------------------------- 046 // Static 047 //------------------------------------------------------------------------------------------------------------------- 048 049 /** 050 * Creates a new builder for this object. 051 * 052 * @param ctx The context creating this session. 053 * @return A new builder. 054 */ 055 public static Builder create(MsgPackParser ctx) { 056 return new Builder(ctx); 057 } 058 059 //------------------------------------------------------------------------------------------------------------------- 060 // Builder 061 //------------------------------------------------------------------------------------------------------------------- 062 063 /** 064 * Builder class. 065 */ 066 @FluentSetters 067 public static class Builder extends InputStreamParserSession.Builder { 068 069 MsgPackParser ctx; 070 071 /** 072 * Constructor 073 * 074 * @param ctx The context creating this session. 075 */ 076 protected Builder(MsgPackParser ctx) { 077 super(ctx); 078 this.ctx = ctx; 079 } 080 081 @Override 082 public MsgPackParserSession build() { 083 return new MsgPackParserSession(this); 084 } 085 086 // <FluentSetters> 087 088 @Override /* GENERATED - org.apache.juneau.ContextSession.Builder */ 089 public <T> Builder apply(Class<T> type, Consumer<T> apply) { 090 super.apply(type, apply); 091 return this; 092 } 093 094 @Override /* GENERATED - org.apache.juneau.ContextSession.Builder */ 095 public Builder debug(Boolean value) { 096 super.debug(value); 097 return this; 098 } 099 100 @Override /* GENERATED - org.apache.juneau.ContextSession.Builder */ 101 public Builder properties(Map<String,Object> value) { 102 super.properties(value); 103 return this; 104 } 105 106 @Override /* GENERATED - org.apache.juneau.ContextSession.Builder */ 107 public Builder property(String key, Object value) { 108 super.property(key, value); 109 return this; 110 } 111 112 @Override /* GENERATED - org.apache.juneau.ContextSession.Builder */ 113 public Builder unmodifiable() { 114 super.unmodifiable(); 115 return this; 116 } 117 118 @Override /* GENERATED - org.apache.juneau.BeanSession.Builder */ 119 public Builder locale(Locale value) { 120 super.locale(value); 121 return this; 122 } 123 124 @Override /* GENERATED - org.apache.juneau.BeanSession.Builder */ 125 public Builder localeDefault(Locale value) { 126 super.localeDefault(value); 127 return this; 128 } 129 130 @Override /* GENERATED - org.apache.juneau.BeanSession.Builder */ 131 public Builder mediaType(MediaType value) { 132 super.mediaType(value); 133 return this; 134 } 135 136 @Override /* GENERATED - org.apache.juneau.BeanSession.Builder */ 137 public Builder mediaTypeDefault(MediaType value) { 138 super.mediaTypeDefault(value); 139 return this; 140 } 141 142 @Override /* GENERATED - org.apache.juneau.BeanSession.Builder */ 143 public Builder timeZone(TimeZone value) { 144 super.timeZone(value); 145 return this; 146 } 147 148 @Override /* GENERATED - org.apache.juneau.BeanSession.Builder */ 149 public Builder timeZoneDefault(TimeZone value) { 150 super.timeZoneDefault(value); 151 return this; 152 } 153 154 @Override /* GENERATED - org.apache.juneau.parser.ParserSession.Builder */ 155 public Builder javaMethod(Method value) { 156 super.javaMethod(value); 157 return this; 158 } 159 160 @Override /* GENERATED - org.apache.juneau.parser.ParserSession.Builder */ 161 public Builder outer(Object value) { 162 super.outer(value); 163 return this; 164 } 165 166 @Override /* GENERATED - org.apache.juneau.parser.ParserSession.Builder */ 167 public Builder schema(HttpPartSchema value) { 168 super.schema(value); 169 return this; 170 } 171 172 @Override /* GENERATED - org.apache.juneau.parser.ParserSession.Builder */ 173 public Builder schemaDefault(HttpPartSchema value) { 174 super.schemaDefault(value); 175 return this; 176 } 177 178 // </FluentSetters> 179 } 180 181 //------------------------------------------------------------------------------------------------------------------- 182 // Instance 183 //------------------------------------------------------------------------------------------------------------------- 184 185 /** 186 * Constructor. 187 * 188 * @param builder The builder for this object. 189 */ 190 protected MsgPackParserSession(Builder builder) { 191 super(builder); 192 } 193 194 @Override /* ParserSession */ 195 protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws IOException, ParseException, ExecutableException { 196 try (MsgPackInputStream is = new MsgPackInputStream(pipe)) { 197 return parseAnything(type, is, getOuter(), null); 198 } 199 } 200 201 /* 202 * Workhorse method. 203 */ 204 private <T> T parseAnything(ClassMeta<?> eType, MsgPackInputStream is, Object outer, BeanPropertyMeta pMeta) throws IOException, ParseException, ExecutableException { 205 206 if (eType == null) 207 eType = object(); 208 ObjectSwap<T,Object> swap = (ObjectSwap<T,Object>)eType.getSwap(this); 209 BuilderSwap<T,Object> builder = (BuilderSwap<T,Object>)eType.getBuilderSwap(this); 210 ClassMeta<?> sType = null; 211 if (builder != null) 212 sType = builder.getBuilderClassMeta(this); 213 else if (swap != null) 214 sType = swap.getSwapClassMeta(this); 215 else 216 sType = eType; 217 218 if (sType.isOptional()) 219 return (T)optional(parseAnything(eType.getElementType(), is, outer, pMeta)); 220 221 setCurrentClass(sType); 222 223 Object o = null; 224 DataType dt = is.readDataType(); 225 int length = (int)is.readLength(); 226 227 if (dt != DataType.NULL) { 228 if (dt == BOOLEAN) 229 o = is.readBoolean(); 230 else if (dt == INT) 231 o = is.readInt(); 232 else if (dt == LONG) 233 o = is.readLong(); 234 else if (dt == FLOAT) 235 o = is.readFloat(); 236 else if (dt == DOUBLE) 237 o = is.readDouble(); 238 else if (dt == STRING) 239 o = trim(is.readString()); 240 else if (dt == BIN) 241 o = is.readBinary(); 242 else if (dt == ARRAY && sType.isObject()) { 243 JsonList jl = new JsonList(this); 244 for (int i = 0; i < length; i++) 245 jl.add(parseAnything(object(), is, outer, pMeta)); 246 o = jl; 247 } else if (dt == MAP && sType.isObject()) { 248 JsonMap jm = new JsonMap(this); 249 for (int i = 0; i < length; i++) 250 jm.put((String)parseAnything(string(), is, outer, pMeta), parseAnything(object(), is, jm, pMeta)); 251 o = cast(jm, pMeta, eType); 252 } 253 254 if (sType.isObject()) { 255 // Do nothing. 256 } else if (sType.isBoolean() || sType.isCharSequence() || sType.isChar() || sType.isNumber() || sType.isByteArray()) { 257 o = convertToType(o, sType); 258 } else if (sType.isMap()) { 259 if (dt == MAP) { 260 Map m = (sType.canCreateNewInstance(outer) ? (Map)sType.newInstance(outer) : newGenericMap(sType)); 261 for (int i = 0; i < length; i++) { 262 Object key = parseAnything(sType.getKeyType(), is, outer, pMeta); 263 ClassMeta<?> vt = sType.getValueType(); 264 Object value = parseAnything(vt, is, m, pMeta); 265 setName(vt, value, key); 266 m.put(key, value); 267 } 268 o = m; 269 } else { 270 throw new ParseException(this, "Invalid data type {0} encountered for parse type {1}", dt, sType); 271 } 272 } else if (builder != null || sType.canCreateNewBean(outer)) { 273 if (dt == MAP) { 274 BeanMap m = builder == null ? newBeanMap(outer, sType.getInnerClass()) : toBeanMap(builder.create(this, eType)); 275 for (int i = 0; i < length; i++) { 276 String pName = parseAnything(string(), is, m.getBean(false), null); 277 BeanPropertyMeta bpm = m.getPropertyMeta(pName); 278 if (bpm == null) { 279 if (pName.equals(getBeanTypePropertyName(eType))) 280 parseAnything(string(), is, null, null); 281 else 282 onUnknownProperty(pName, m, parseAnything(string(), is, null, null)); 283 } else { 284 ClassMeta<?> cm = bpm.getClassMeta(); 285 Object value = parseAnything(cm, is, m.getBean(false), bpm); 286 setName(cm, value, pName); 287 try { 288 bpm.set(m, pName, value); 289 } catch (BeanRuntimeException e) { 290 onBeanSetterException(pMeta, e); 291 throw e; 292 } 293 } 294 } 295 o = builder == null ? m.getBean() : builder.build(this, m.getBean(), eType); 296 } else { 297 throw new ParseException(this, "Invalid data type {0} encountered for parse type {1}", dt, sType); 298 } 299 } else if (sType.canCreateNewInstanceFromString(outer) && dt == STRING) { 300 o = sType.newInstanceFromString(outer, o == null ? "" : o.toString()); 301 } else if (sType.isCollection()) { 302 if (dt == MAP) { 303 JsonMap m = new JsonMap(this); 304 for (int i = 0; i < length; i++) 305 m.put((String)parseAnything(string(), is, outer, pMeta), parseAnything(object(), is, m, pMeta)); 306 o = cast(m, pMeta, eType); 307 } else if (dt == ARRAY) { 308 Collection l = ( 309 sType.canCreateNewInstance(outer) 310 ? (Collection)sType.newInstance() 311 : new JsonList(this) 312 ); 313 for (int i = 0; i < length; i++) 314 l.add(parseAnything(sType.getElementType(), is, l, pMeta)); 315 o = l; 316 } else { 317 throw new ParseException(this, "Invalid data type {0} encountered for parse type {1}", dt, sType); 318 } 319 } else if (sType.isArray() || sType.isArgs()) { 320 if (dt == MAP) { 321 JsonMap m = new JsonMap(this); 322 for (int i = 0; i < length; i++) 323 m.put((String)parseAnything(string(), is, outer, pMeta), parseAnything(object(), is, m, pMeta)); 324 o = cast(m, pMeta, eType); 325 } else if (dt == ARRAY) { 326 Collection l = ( 327 sType.isCollection() && sType.canCreateNewInstance(outer) 328 ? (Collection)sType.newInstance() 329 : new JsonList(this) 330 ); 331 for (int i = 0; i < length; i++) 332 l.add(parseAnything(sType.isArgs() ? sType.getArg(i) : sType.getElementType(), is, l, pMeta)); 333 o = toArray(sType, l); 334 } else { 335 throw new ParseException(this, "Invalid data type {0} encountered for parse type {1}", dt, sType); 336 } 337 } else if (dt == MAP) { 338 JsonMap m = new JsonMap(this); 339 for (int i = 0; i < length; i++) 340 m.put((String)parseAnything(string(), is, outer, pMeta), parseAnything(object(), is, m, pMeta)); 341 if (m.containsKey(getBeanTypePropertyName(eType))) 342 o = cast(m, pMeta, eType); 343 else if (sType.getProxyInvocationHandler() != null) 344 o = newBeanMap(outer, sType.getInnerClass()).load(m).getBean(); 345 else 346 throw new ParseException(this, "Class ''{0}'' could not be instantiated. Reason: ''{1}''", 347 sType.getInnerClass().getName(), sType.getNotABeanReason()); 348 } else { 349 throw new ParseException(this, "Invalid data type {0} encountered for parse type {1}", dt, sType); 350 } 351 } 352 353 if (swap != null && o != null) 354 o = unswap(swap, o, eType); 355 356 if (outer != null) 357 setParent(eType, o, outer); 358 359 return (T)o; 360 } 361}