2016-01-23 8 views
6

Ho un requisito in cui ho creato un'annotazione personalizzata @MaskSensitiveData. Annoto campi sensibili. likePersonalizza Jackson ObjectMapper per leggere annotazioni personalizzate e campi maschera annotati

class MyBean { 
    String userName; 
    @MaskSensitiveData 
    String cardNumber; 
    String abc; 
    String xyz; 
} 

ObjectMapper mapper = new ObjectMapper(); 
    String json = null; 
    AnnotationIntrospector primary = new JaxbAnnotationIntrospector(); 
    AnnotationIntrospector secondary = new JacksonAnnotationIntrospector(); 
    AnnotationIntrospector pair = new AnnotationIntrospectorPair(primary, secondary); 
    mapper.setAnnotationIntrospector(pair); 
    try { 
     json = mapper.writeValueAsString(obj); 
     /* 
     * if(json != null) { json = getLoggableString(json); } 
     */ 
    } catch (Exception e) { 
     return "Unable to convert to Json object:" + obj.toString() + " Message: " + e.getMessage(); 

    } 

Sto usando Jackson ObjectMapper per convertire objct in Json come. Ho bisogno di personalizzare Object Mapper per mascherare il campo cardNumber in risposta json. Si prega di suggerire un modo migliore.

risposta

0
package stackoverflow; 

import static org.hamcrest.MatcherAssert.assertThat; 
import static org.hamcrest.Matchers.is; 

import java.io.IOException; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 

import org.hamcrest.Matchers; 
import org.junit.Test; 

import com.fasterxml.jackson.core.JsonGenerator; 
import com.fasterxml.jackson.core.JsonParser; 
import com.fasterxml.jackson.core.JsonProcessingException; 
import com.fasterxml.jackson.databind.AnnotationIntrospector; 
import com.fasterxml.jackson.databind.DeserializationContext; 
import com.fasterxml.jackson.databind.ObjectMapper; 
import com.fasterxml.jackson.databind.SerializerProvider; 
import com.fasterxml.jackson.databind.deser.std.StdDeserializer; 
import com.fasterxml.jackson.databind.introspect.Annotated; 
import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair; 
import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector; 
import com.fasterxml.jackson.databind.ser.std.StdSerializer; 

public class MaskingAnnotationExample { 
    // Define @custom Annotation 
    // assumed to be used by String type field for this example 
    @Retention(RetentionPolicy.RUNTIME) 
    static @interface MaskSensitiveData { 
    } 

    public static class MyBean { 
     private String userName; 

     @MaskSensitiveData 
     private String cardNumber; 

     public MyBean() { 
     } 

     public String getCardNumber() { 
      return cardNumber; 
     } 

     public String getUserName() { 
      return userName; 
     } 

     public void setUserName(String userName) { 
      this.userName = userName; 
     } 

     public void setCardNumber(String cardNumber) { 
      this.cardNumber = cardNumber; 
     } 
    } 

    // map the Serializer/Deserializer based on custom annotation 
    public static class MaskSensitiveDataAnnotationIntrospector extends NopAnnotationIntrospector { 
     private static final long serialVersionUID = 1L; 

     @Override 
     public Object findSerializer(Annotated am) { 
      MaskSensitiveData annotation = am.getAnnotation(MaskSensitiveData.class); 
      if (annotation != null) { 
       return MaskSensitiveDataSerializer.class; 
      } 

      return null; 
     } 

     @Override 
     public Object findDeserializer(Annotated am) { 
      MaskSensitiveData annotation = am.getAnnotation(MaskSensitiveData.class); 
      if (annotation != null) { 
       return MaskSensitiveDataDeserializer.class; 
      } 

      return null; 
     } 
    } 

    public static class MaskSensitiveDataDeserializer extends StdDeserializer<String> { 
     private static final long serialVersionUID = 1L; 

     public MaskSensitiveDataDeserializer() { 
      super(String.class); 
     } 

     @Override 
     public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { 
      // un-masking logic here. in our example we are removing "MASK" 
      // string 
      String s = p.getValueAsString(); 
      return s.substring(4); 
     } 
    } 

    public static class MaskSensitiveDataSerializer extends StdSerializer<String> { 
     private static final long serialVersionUID = 1L; 

     public MaskSensitiveDataSerializer() { 
      super(String.class); 
     } 

     @Override 
     public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException { 
      // Masking data; for our example we are adding 'MASK' 
      gen.writeString("MASK" + value); 
     } 
    } 

    @Test 
    public void demo() throws Exception { 
     ObjectMapper mapper = new ObjectMapper(); 

     AnnotationIntrospector sis = mapper.getSerializationConfig().getAnnotationIntrospector(); 
     AnnotationIntrospector dis = mapper.getDeserializationConfig().getAnnotationIntrospector(); 

     AnnotationIntrospector is1 = AnnotationIntrospectorPair.pair(sis, new MaskSensitiveDataAnnotationIntrospector()); 
     AnnotationIntrospector is2 = AnnotationIntrospectorPair.pair(dis, new MaskSensitiveDataAnnotationIntrospector()); 

     mapper.setAnnotationIntrospectors(is1, is2); 

     MyBean obj = new MyBean(); 
     obj.setUserName("Saurabh Bhardwaj"); 
     obj.setCardNumber("4455-7788-9999-7777"); 
     String json = mapper.writeValueAsString(obj); 

     String expectedJson = "{\"userName\":\"Saurabh Bhardwaj\",\"cardNumber\":\"MASK4455-7788-9999-7777\"}"; 
     assertThat(json, Matchers.is(expectedJson)); 

     MyBean cloned = mapper.readValue(json, MyBean.class); 
     assertThat(cloned.getCardNumber(), is(obj.getCardNumber())); 
    } 
} 

Spero che questo aiuti.

2

Ecco una soluzione al problema utilizzando JsonSerializer personalizzato. I passaggi sono seguiti da questo blog post.

Creare un serializzatore personalizzato

public class MaskingSerializer extends JsonSerializer <MyBean> { 

    @ 
    Override 
    public void serialize(MyBean value, JsonGenerator jGen, SerializerProvider serializers) throws IOException, JsonProcessingException { 
    jGen.writeStartObject(); 

    Field[] fields = value.getClass().getDeclaredFields(); 
    for (Field field: fields) { 
     field.setAccessible(true); 
     MaskSensitiveData mask = field.getDeclaredAnnotation(MaskSensitiveData.class); 

     try { 
     if (mask != null) { 
      field.setAccessible(true); 
      field.set(value, field.get(value).toString().replaceAll(".", "*")); 
     } 

     jGen.writeStringField(field.getName(), field.get(value).toString()); 


     } catch (IllegalArgumentException e) { 
     e.printStackTrace(); 
     } catch (IllegalAccessException e) { 
     e.printStackTrace(); 
     } 
    } 

    jGen.writeEndObject(); 

    } 

} 

Creare un modulo per impacchettare il serializzatore

public class MaskingModule extends SimpleModule { 
    private static final String NAME = "CustomIntervalModule"; 
    private static final VersionUtil VERSION_UTIL = new VersionUtil() {}; 

    public MaskingModule() { 
     super(NAME, VERSION_UTIL.version()); 
     addSerializer(MyBean.class, new MaskingSerializer()); 
    } 
} 

Registrare il modulo con ObjectMapper.

public class CustomObjectMapper extends ObjectMapper { 
    public CustomObjectMapper() { 
     registerModule(new MaskingModule()); 
    } 
    } 

prova il codice

public class MyBeanTest { 

    private static final CustomObjectMapper OBJECT_MAPPER = 
      new CustomObjectMapper(); 
    @Test 
    public void testIntervalSerialization() throws Exception { 
     MyBean mb = new MyBean(); 
     mb.setAbc("value"); 
     mb.setCardNumber("4441114443335551"); 
     mb.setUserName("User"); 
     mb.setXyz("value"); 
     String result = OBJECT_MAPPER.writeValueAsString(mb); 
     System.out.println(result); 
     String expected = "{\"userName\":\"User\",\"cardNumber\":\"****************\",\"abc\":\"value\",\"xyz\":\"value\"}"; 
     Assert.assertEquals(expected, result); 
    } 
} 
+0

Questo va bene finché tutti gli attributi sono di tipo String. Se tu avessi abc come un tipo più complesso con i suoi attributi, come li stamperesti come json? Ho anche questo problema e non so ancora la soluzione ... – dune76

+0

https://stackoverflow.com/q/46021769/5667890 questo è il mio problema attuale e non ho ancora un indizio – dune76

Problemi correlati