Исключить поля в json Использование Jackson и Json-View

Я использую json-view для создания динамического json по моей потребности, это отличная библиотека, я использую эту библиотеку для сейчас. Недавно я столкнулся с проблемой с моим одним из случаев использования, позвольте мне сначала поставить мой код

Класс пользователя

public class User {

    private String name;
    private String emailId;
    private String mobileNo;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmailId() {
        return emailId;
    }

    public void setEmailId(String emailId) {
        this.emailId = emailId;
    }

    public String getMobileNo() {
        return mobileNo;
    }

    public void setMobileNo(String mobileNo) {
        this.mobileNo = mobileNo;
    }

}

Класс ScreenInfoPojo

public class ScreenInfoPojo {

    private Long id;
    private String name;
    private ScreenInfoPojo parentScreen;
    private User createdBy;
    private User lastUpdatedBy;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public ScreenInfoPojo getParentScreen() {
        return parentScreen;
    }

    public void setParentScreen(ScreenInfoPojo parentScreen) {
        this.parentScreen = parentScreen;
    }



    public User getCreatedBy() {
        return createdBy;
    }

    public void setCreatedBy(User createdBy) {
        this.createdBy = createdBy;
    }

    public User getLastUpdatedBy() {
        return lastUpdatedBy;
    }

    public void setLastUpdatedBy(User lastUpdatedBy) {
        this.lastUpdatedBy = lastUpdatedBy;
    } 

Код запуска

public class TestMain {
    public static void main(String[] args) throws JsonProcessingException {
        User user=new User();
        user.setName("ABC");
        user.setEmailId("[email protected]");
        user.setMobileNo("123456789");

        ScreenInfoPojo screen1=new ScreenInfoPojo();
        screen1.setId(1l);
        screen1.setName("Screen1");
        screen1.setCreatedBy(user);
        screen1.setLastUpdatedBy(user);

        ScreenInfoPojo screen2=new ScreenInfoPojo();
        screen2.setId(2l);
        screen2.setName("Screen2");
        screen2.setParentScreen(Screen1);
        screen2.setCreatedBy(user);
        screen2.setLastUpdatedBy(user);

        ScreenInfoPojo screen3=new ScreenInfoPojo();
        screen3.setId(3l);
        screen3.setName("Screen3");
        screen3.setParentScreen(Screen2);
        screen3.setCreatedBy(user);
        screen3.setLastUpdatedBy(user);

        ScreenInfoPojo screen4=new ScreenInfoPojo();
        screen4.setId(4l);
        screen4.setName("Screen4");
        screen4.setParentScreen(Screen3);
        screen4.setCreatedBy(user);
        screen4.setLastUpdatedBy(user);

        List<ScreenInfoPojo> screens=new ArrayList<>();
        screens.add(screen1);
        screens.add(screen2);
        screens.add(screen3);
        screens.add(screen4);

        ObjectMapper mapper = new ObjectMapper().registerModule(new JsonViewModule());
        String json = mapper.writeValueAsString(JsonView.with(screens).onClass(ScreenInfoPojo.class, Match.match()
                .exclude("*")
                .include("id","name","createdBy.name","lastUpdatedBy.mobileNo","parentScreen.id")));
        System.out.println("json"+json);
    }    

Результат

[{
    "id": 1,
    "name": "Screen1",
    "parentScreen": null,
    "createdBy": {
        "name": "ABC"
    },
    "lastUpdatedBy": {
        "mobileNo": "123456789"
    }
}, {
    "id": 2,
    "name": "Screen2",
    "parentScreen": {
        "id": 1,
        "name": "Screen1",
        "parentScreen": null,
        "createdBy": {},
        "lastUpdatedBy": {}
    },
    "createdBy": {
        "name": "ABC"
    },
    "lastUpdatedBy": {
        "mobileNo": "123456789"
    }
}, {
    "id": 3,
    "name": "Screen3",
    "parentScreen": {
        "id": 2,
        "name": "Screen2",
        "parentScreen": {
            "id": 1,
            "name": "Screen1",
            "parentScreen": null,
            "createdBy": {},
            "lastUpdatedBy": {}
        },
        "createdBy": {},
        "lastUpdatedBy": {}
    },
    "createdBy": {
        "name": "ABC"
    },
    "lastUpdatedBy": {
        "mobileNo": "123456789"
    }
}, {
    "id": 4,
    "name": "Screen4",
    "parentScreen": {
        "id": 3,
        "name": "Screen3",
        "parentScreen": {
            "id": 2,
            "name": "Screen2",
            "parentScreen": {
                "id": 1,
                "name": "Screen1",
                "parentScreen": null,
                "createdBy": {},
                "lastUpdatedBy": {}
            },
            "createdBy": {},
            "lastUpdatedBy": {}
        },
        "createdBy": {},
        "lastUpdatedBy": {}
    },
    "createdBy": {
        "name": "ABC"
    },
    "lastUpdatedBy": {
        "mobileNo": "123456789"
    }
}]

Ожидаемый результат

[{
    "id": 1,
    "name": "Screen1",
    "parentScreen": null,
    "createdBy": {
        "name": "ABC"
    },
    "lastUpdatedBy": {
        "mobileNo": "123456789"
    }
}, {
    "id": 2,
    "name": "Screen2",
    "parentScreen": {
        "id": 1
    },
    "createdBy": {
        "name": "ABC"
    },
    "lastUpdatedBy": {
        "mobileNo": "123456789"
    }
}, {
    "id": 3,
    "name": "Screen3",
    "parentScreen": {
        "id": 2
    },
    "createdBy": {
        "name": "ABC"
    },
    "lastUpdatedBy": {
        "mobileNo": "123456789"
    }
}, {
    "id": 4,
    "name": "Screen4",
    "parentScreen": {
        "id": 3
    },
    "createdBy": {
        "name": "ABC"
    },
    "lastUpdatedBy": {
        "mobileNo": "123456789"
    }
}]

Проблема

В моем случае использования у меня есть класс ScreenInfoPojo, который относится к тому же классу, что и parentScreen, Я пытаюсь получить определенные поля/поля родительского ("parentScreen.id" ) instate. Я получаю все поля, которые я определил на объекте child/target ( "id", "name", "createdBy.name", "lastUpdatedBy.mobileNo", "parentScreen.id" ), а родительский ответ снова рекурсивный! Одна вещь, которую я заметил, что это происходит только в том случае, если класс имеет свою собственную ссылку, я поместил ссылку Пользователь как два разных поля createdBy и lastUpdatedBy strong > и попытался получить "имя" и "mobileNo" , и они отлично работали.

Любое предложение решить эту проблему будет действительно полезно!!!!

Спасибо

Ответ 1

Да. Предложение Include не работает для ссылки на тот же класс.

Что вы можете сделать?

Скомпилировать из источника в соответствии с инструкцией github построить из источника

Функция обновления JsonViewSerializer.JsonWriter.fieldAllowed

находка:

        if(match == null) {
            match = this.currentMatch;
        } else {
            prefix = "";
        }

и комментарий else

        if(match == null) {
            match = this.currentMatch;
        } else {
            //prefix = "";
        }

Вы получите ожидаемый результат. Но. Я не знаю, как это повлияет на другие фильтры.

Чтобы иметь больше контроля, вы можете добавить свойство в класс JsonView.

Например:

в JsonView add:

private boolean ignorePathIfClassRegistered = true;

     public boolean isIgnorePathIfClassRegistered() {
            return ignorePathIfClassRegistered;
        }

        public JsonView1<T>  setIgnorePathIfClassRegistered(boolean ignorePathIfClassRegistered) {
            this.ignorePathIfClassRegistered = ignorePathIfClassRegistered;
            return this;
        }

В JsonViewSerializer.JsonWriter.fieldAllowed функция переписать if, чтобы:

        if(match == null) {
            match = this.currentMatch;
        } else {
            if (result.isIgnorePathIfClassRegistered())
            prefix = "";
        }

И вы можете использовать его в своем примере, например:

JsonView<List<ScreenInfoPojo>> viwevedObject = JsonView
        .with(screens)
        .onClass(ScreenInfoPojo.class,
                Match.match()
                        .exclude("*")
                        .include("id","name")
                        .include("createdBy.name")
                        .include("lastUpdatedBy.mobileNo")
                        .include("parentScreen.id"))
        .setIgnorePathIfClassRegistered(false);

ObjectMapper mapper = new ObjectMapper().registerModule(new JsonViewModule());
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);

String json = mapper.writeValueAsString(viwevedObject);

Ответ 2

Вы можете просто использовать аннотацию jackson @jsonignore в поле, которое вы не хотите в ответ json.

Я не знаю, можете или нет использовать какие-либо аннотации к вашему коду. Если так, это бесполезно.

Ответ 3

Наиболее гибким способом сериализации объекта является создание настраиваемого сериализатора.

Если я правильно понял ваши требования, может работать следующий сериализатор:

public class CustomScreenInfoSerializer extends JsonSerializer<ScreenInfoPojo> {

    @Override
    public void serialize(ScreenInfoPojo value, JsonGenerator gen, SerializerProvider serializers)
            throws IOException, JsonProcessingException {
        gen.writeStartObject();
        gen.writeNumberField("id", value.getId());
        gen.writeStringField("name", value.getName());
        gen.writeFieldName("createdBy");
        gen.writeStartObject();
        gen.writeStringField("name", value.getCreatedBy().getName());
        gen.writeEndObject();
        gen.writeFieldName("lastUpdatedBy");
        gen.writeStartObject();
        gen.writeStringField("mobileNo", value.getLastUpdatedBy().getMobileNo());
        gen.writeEndObject();
        if (value.getParentScreen() == null) {
            gen.writeNullField("parentScreen");
        }
        else {
            gen.writeFieldName("parentScreen");
            gen.writeStartObject();
            gen.writeNumberField("id", value.getParentScreen().getId());
            gen.writeEndObject();
        }
        gen.writeEndObject();

    }

}

Используя

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(ScreenInfoPojo.class, new CustomScreenInfoSerializer());
mapper.registerModule(module);
String json = mapper.writeValueAsString(screens);
System.out.println(json);

производит

[
   {
      "id": 1,
      "name": "Screen1",
      "createdBy": {
         "name": "ABC"
      },
      "lastUpdatedBy": {
         "mobileNo": "123456789"
      },
      "parentScreen": null
   },
   {
      "id": 2,
      "name": "Screen2",
      "createdBy": {
         "name": "ABC"
      },
      "lastUpdatedBy": {
         "mobileNo": "123456789"
      },
      "parentScreen": {
         "id": 1
      }
   },
   {
      "id": 3,
      "name": "Screen3",
      "createdBy": {
         "name": "ABC"
      },
      "lastUpdatedBy": {
         "mobileNo": "123456789"
      },
      "parentScreen": {
         "id": 2
      }
   },
   {
      "id": 4,
      "name": "Screen4",
      "createdBy": {
         "name": "ABC"
      },
      "lastUpdatedBy": {
         "mobileNo": "123456789"
      },
      "parentScreen": {
         "id": 3
      }
   }
]