protected Object _unwrapAndDeserialize(
     JsonParser jp, DeserializationContext ctxt, JavaType rootType, JsonDeserializer<Object> deser)
     throws IOException, JsonParseException, JsonMappingException {
   SerializedString rootName = _provider.findExpectedRootName(ctxt.getConfig(), rootType);
   if (jp.getCurrentToken() != JsonToken.START_OBJECT) {
     throw JsonMappingException.from(
         jp,
         "Current token not START_OBJECT (needed to unwrap root name '"
             + rootName
             + "'), but "
             + jp.getCurrentToken());
   }
   if (jp.nextToken() != JsonToken.FIELD_NAME) {
     throw JsonMappingException.from(
         jp,
         "Current token not FIELD_NAME (to contain expected root name '"
             + rootName
             + "'), but "
             + jp.getCurrentToken());
   }
   String actualName = jp.getCurrentName();
   if (!rootName.getValue().equals(actualName)) {
     throw JsonMappingException.from(
         jp,
         "Root name '"
             + actualName
             + "' does not match expected ('"
             + rootName
             + "') for type "
             + rootType);
   }
   // ok, then move to value itself....
   jp.nextToken();
   Object result;
   if (_valueToUpdate == null) {
     result = deser.deserialize(jp, ctxt);
   } else {
     deser.deserialize(jp, ctxt, _valueToUpdate);
     result = _valueToUpdate;
   }
   // and last, verify that we now get matching END_OBJECT
   if (jp.nextToken() != JsonToken.END_OBJECT) {
     throw JsonMappingException.from(
         jp,
         "Current token not END_OBJECT (to match wrapper object with root name '"
             + rootName
             + "'), but "
             + jp.getCurrentToken());
   }
   return result;
 }
  /** Method called to locate deserializer for the passed root-level value. */
  protected JsonDeserializer<Object> _findRootDeserializer(
      DeserializationConfig cfg, JavaType valueType) throws JsonMappingException {
    // First: have we already seen it?
    JsonDeserializer<Object> deser = _rootDeserializers.get(valueType);
    if (deser != null) {
      return deser;
    }

    // Nope: need to ask provider to resolve it
    deser = _provider.findTypedValueDeserializer(cfg, valueType, null);
    if (deser == null) { // can this happen?
      throw new JsonMappingException("Can not find a deserializer for type " + valueType);
    }
    _rootDeserializers.put(valueType, deser);
    return deser;
  }