@Override
  public PropertyName findNameForDeserialization(Annotated a) {
    String name;

    // @JsonSetter has precedence over @JsonProperty, being more specific
    // @JsonDeserialize implies that there is a property, but no name
    JsonSetter js = _findAnnotation(a, JsonSetter.class);
    if (js != null) {
      name = js.value();
    } else {
      JsonProperty pann = _findAnnotation(a, JsonProperty.class);
      if (pann != null) {
        name = pann.value();
        /* 22-Apr-2014, tatu: Should figure out a better way to do this, but
         *   it's actually bit tricky to do it more efficiently (meta-annotations
         *   add more lookups; AnnotationMap costs etc)
         */
      } else if (_hasAnnotation(a, JsonDeserialize.class)
          || _hasAnnotation(a, JsonView.class)
          || _hasAnnotation(a, JsonUnwrapped.class) // [#442]
          || _hasAnnotation(a, JsonBackReference.class)
          || _hasAnnotation(a, JsonManagedReference.class)) {
        name = "";
      } else {
        return null;
      }
    }
    return PropertyName.construct(name);
  }
 @Override
 public Boolean hasRequiredMarker(AnnotatedMember m) {
   JsonProperty ann = _findAnnotation(m, JsonProperty.class);
   if (ann != null) {
     return ann.required();
   }
   return null;
 }
 @Override
 public String findPropertyDefaultValue(Annotated ann) {
   JsonProperty prop = _findAnnotation(ann, JsonProperty.class);
   if (prop == null) {
     return null;
   }
   String str = prop.defaultValue();
   // Since annotations do not allow nulls, need to assume empty means "none"
   return str.isEmpty() ? null : str;
 }
 @Override
 public Integer findPropertyIndex(Annotated ann) {
   JsonProperty prop = _findAnnotation(ann, JsonProperty.class);
   if (prop != null) {
     int ix = prop.index();
     if (ix != JsonProperty.INDEX_UNKNOWN) {
       return Integer.valueOf(ix);
     }
   }
   return null;
 }
  public void testDumpConfiguratioWithoutDefaults() throws IOException {
    // check for case when default resources are not loaded
    Configuration config = new Configuration(false);
    StringWriter outWriter = new StringWriter();
    Configuration.dumpConfiguration(config, outWriter);
    String jsonStr = outWriter.toString();
    ObjectMapper mapper = new ObjectMapper();
    JsonConfiguration jconf = mapper.readValue(jsonStr, JsonConfiguration.class);

    // ensure that no properties are loaded.
    assertEquals(0, jconf.getProperties().length);

    // add 2 keys
    out = new BufferedWriter(new FileWriter(CONFIG));
    startConfig();
    appendProperty("test.key1", "value1");
    appendProperty("test.key2", "value2", true);
    endConfig();
    Path fileResource = new Path(CONFIG);
    config.addResource(fileResource);
    out.close();

    outWriter = new StringWriter();
    Configuration.dumpConfiguration(config, outWriter);
    jsonStr = outWriter.toString();
    mapper = new ObjectMapper();
    jconf = mapper.readValue(jsonStr, JsonConfiguration.class);

    HashMap<String, JsonProperty> confDump = new HashMap<String, JsonProperty>();
    for (JsonProperty prop : jconf.getProperties()) {
      confDump.put(prop.getKey(), prop);
    }
    // ensure only 2 keys are loaded
    assertEquals(2, jconf.getProperties().length);
    // ensure the values are consistent
    assertEquals(confDump.get("test.key1").getValue(), "value1");
    assertEquals(confDump.get("test.key2").getValue(), "value2");
    // check the final tag
    assertEquals(false, confDump.get("test.key1").getIsFinal());
    assertEquals(true, confDump.get("test.key2").getIsFinal());
    // check the resource for each property
    for (JsonProperty prop : jconf.getProperties()) {
      assertEquals(fileResource.toString(), prop.getResource());
    }
  }
  @Override
  public PropertyName findNameForSerialization(Annotated a) {
    String name = null;

    JsonGetter jg = _findAnnotation(a, JsonGetter.class);
    if (jg != null) {
      name = jg.value();
    } else {
      JsonProperty pann = _findAnnotation(a, JsonProperty.class);
      if (pann != null) {
        name = pann.value();
      } else if (_hasAnnotation(a, JsonSerialize.class)
          || _hasAnnotation(a, JsonView.class)
          || _hasAnnotation(a, JsonRawValue.class)) {
        name = "";
      } else {
        return null;
      }
    }
    return PropertyName.construct(name);
  }
  public void testDumpConfiguration() throws IOException {
    StringWriter outWriter = new StringWriter();
    Configuration.dumpConfiguration(conf, outWriter);
    String jsonStr = outWriter.toString();
    ObjectMapper mapper = new ObjectMapper();
    JsonConfiguration jconf = mapper.readValue(jsonStr, JsonConfiguration.class);
    int defaultLength = jconf.getProperties().length;

    // add 3 keys to the existing configuration properties
    out = new BufferedWriter(new FileWriter(CONFIG));
    startConfig();
    appendProperty("test.key1", "value1");
    appendProperty("test.key2", "value2", true);
    appendProperty("test.key3", "value3");
    endConfig();
    Path fileResource = new Path(CONFIG);
    conf.addResource(fileResource);
    out.close();

    outWriter = new StringWriter();
    Configuration.dumpConfiguration(conf, outWriter);
    jsonStr = outWriter.toString();
    mapper = new ObjectMapper();
    jconf = mapper.readValue(jsonStr, JsonConfiguration.class);
    int length = jconf.getProperties().length;
    // check for consistency in the number of properties parsed in Json format.
    assertEquals(length, defaultLength + 3);

    // change few keys in another resource file
    out = new BufferedWriter(new FileWriter(CONFIG2));
    startConfig();
    appendProperty("test.key1", "newValue1");
    appendProperty("test.key2", "newValue2");
    endConfig();
    Path fileResource1 = new Path(CONFIG2);
    conf.addResource(fileResource1);
    out.close();

    outWriter = new StringWriter();
    Configuration.dumpConfiguration(conf, outWriter);
    jsonStr = outWriter.toString();
    mapper = new ObjectMapper();
    jconf = mapper.readValue(jsonStr, JsonConfiguration.class);

    // put the keys and their corresponding attributes into a hashmap for their
    // efficient retrieval
    HashMap<String, JsonProperty> confDump = new HashMap<String, JsonProperty>();
    for (JsonProperty prop : jconf.getProperties()) {
      confDump.put(prop.getKey(), prop);
    }
    // check if the value and resource of test.key1 is changed
    assertEquals("newValue1", confDump.get("test.key1").getValue());
    assertEquals(false, confDump.get("test.key1").getIsFinal());
    assertEquals(fileResource1.toString(), confDump.get("test.key1").getResource());
    // check if final parameter test.key2 is not changed, since it is first
    // loaded as final parameter
    assertEquals("value2", confDump.get("test.key2").getValue());
    assertEquals(true, confDump.get("test.key2").getIsFinal());
    assertEquals(fileResource.toString(), confDump.get("test.key2").getResource());
    // check for other keys which are not modified later
    assertEquals("value3", confDump.get("test.key3").getValue());
    assertEquals(false, confDump.get("test.key3").getIsFinal());
    assertEquals(fileResource.toString(), confDump.get("test.key3").getResource());
    // check for resource to be "Unknown" for keys which are loaded using 'set'
    // and expansion of properties
    conf.set("test.key4", "value4");
    conf.set("test.key5", "value5");
    conf.set("test.key6", "${test.key5}");
    outWriter = new StringWriter();
    Configuration.dumpConfiguration(conf, outWriter);
    jsonStr = outWriter.toString();
    mapper = new ObjectMapper();
    jconf = mapper.readValue(jsonStr, JsonConfiguration.class);
    confDump = new HashMap<String, JsonProperty>();
    for (JsonProperty prop : jconf.getProperties()) {
      confDump.put(prop.getKey(), prop);
    }
    assertEquals("value5", confDump.get("test.key6").getValue());
    assertEquals("programatically", confDump.get("test.key4").getResource());
    outWriter.close();
  }