最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - Masking applied to exceptions unexpectedly - Stack Overflow

programmeradmin3浏览0评论

I'm running into a strange situation where if an exception is thrown when calling an endpoint in my application, the exception details are masked.

This is unexpected behavior because I only want to apply the masking for certain fields in my objects.

Here's the code I have setup so far:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Masked {
}

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;

public class MaskingSerializer extends JsonSerializer<String> {

    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (value != null) {
            gen.writeString(value.replaceAll("(?<=.{4}).", "*"));
        } else {
            gen.writeNull();
        }
    }
}

//JacksonConfig
@Bean
public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
 return builder -> builder.modules(new SimpleModule().addSerializer(String.class, new MaskingSerializer()));
}

//Use annotation like below
@Masked
@JsonSerialize(using = MaskingSerializer.class)
private String sensitiveField;

Sample JSON with masking that shouldn't be happening:

{
    "timestamp": "2025-03-16T21:03:46.796+00:00",
    "status": 404,
    "error": "Not *****",
    "message": "No s******************************************************",
    "path": "/man***********************************"
}

I expect only when I use @Masked annotation then the masking is applied (only on serializing field level) but I noticed if there's an error in an api call, the response back is masked per this rule which is odd. Why does this happen?

I'm running into a strange situation where if an exception is thrown when calling an endpoint in my application, the exception details are masked.

This is unexpected behavior because I only want to apply the masking for certain fields in my objects.

Here's the code I have setup so far:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Masked {
}

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;

public class MaskingSerializer extends JsonSerializer<String> {

    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (value != null) {
            gen.writeString(value.replaceAll("(?<=.{4}).", "*"));
        } else {
            gen.writeNull();
        }
    }
}

//JacksonConfig
@Bean
public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
 return builder -> builder.modules(new SimpleModule().addSerializer(String.class, new MaskingSerializer()));
}

//Use annotation like below
@Masked
@JsonSerialize(using = MaskingSerializer.class)
private String sensitiveField;

Sample JSON with masking that shouldn't be happening:

{
    "timestamp": "2025-03-16T21:03:46.796+00:00",
    "status": 404,
    "error": "Not *****",
    "message": "No s******************************************************",
    "path": "/man***********************************"
}

I expect only when I use @Masked annotation then the masking is applied (only on serializing field level) but I noticed if there's an error in an api call, the response back is masked per this rule which is odd. Why does this happen?

Share Improve this question edited Mar 16 at 21:27 Foobar asked Mar 16 at 16:22 FoobarFoobar 137 bronze badges 3
  • This question is ambiguous, but both interpretations lack detail. [A] If you understand why the masking is being triggered but do not understand why it is masking your exception trace in the way that it is, this question needs to include an exception trace that is masked and optimally, what it looked like before. You can edit your MaskingSerializer to accomplish this. Or, [B] you do not understand why the masking is being applied. In which case we need the config, the code that throws it, and how the exception ends up serialized in the first place. – rzwitserloot Commented Mar 16 at 16:56
  • 1 Rereading your question it seems like it's [B]: You don't know why it is applied. Well... we don't know either, you haven't provided the code that uses the @Masked annotation or how you've configured things. This question boils down to 'how do I use JsonSerializer which is too broad; but that might be good news for you: There are plenty of tutorials :) – rzwitserloot Commented Mar 16 at 16:58
  • Sorry, I edited my post now. – Foobar Commented Mar 16 at 20:04
Add a comment  | 

1 Answer 1

Reset to default 1

This is the problematic line:

.addSerializer(String.class, new MaskingSerializer()));

That tells the serializer to serialize all String objects with the provided serializer. error, message, and path are all strings, so they are all serialized with your MaskingSerializer.

Your intent is that only fields annotated with @Masked should be serialized with it.

You've made a Masked annotation but absolutely nowhere in your code is that linked to MaskingSerializer. You did add @JsonSerialize(using = MaskingSerializer.class) which would work fine - just.. do not add that serializer.

That's one simple way to accomplish your goal: Do use @JsonSerialize, ditch @Masked (you aren't using it at all), and do not register the serializer as that would then apply it to every String.

If you actually want that annotation, you would register the serializer but it needs a filtering operation: It needs to check if the field it is trying to serialize has the annotation. To do this, you need to make a ContextualSerializer instead, and write in your impl of the createContextual method a check on whether a @Masked annotation is present (via the property param you will receive; it has a getAnnotations() method), and then return either the default string serializer if it is not present, or your masked serializer if it is.

Serialization is a complex beast and it seems like you think it isn't and just sort of haphazardly strung some annotations and calls together in the vein hope that it'll all just sort of work. Serialization is like that: It seems so simple. It just isn't. Reading the docs is important. Be aware that fully understanding what it all implies is difficult even if you do. Anytime you think 'this is too complicated; surely it is simpler' suppress that thought for it will lead you astray: It isn't simple at all.

发布评论

评论列表(0)

  1. 暂无评论