简体   繁体   English

注释@NotNull 不适用于值对象

[英]Annotation @NotNull not working on value objects

In one of my spring boot's @RestController methods I'm getting a json object in @RequestBody .在我的 spring 引导的@RestController方法之一中,我在@RequestBody中得到了 json object 。

I want the fields in this object to be not null, that is they should always have non-blank value.我希望此 object 中的字段不是 null,即它们应该始终具有非空白值。

Based on many answers like these , I tried to use @NotNull, @NotEmpty, @JsonProperty(required = true) on fields, but it is not working.基于这些类似的许多答案,我尝试在字段上使用@NotNull, @NotEmpty, @JsonProperty(required = true) ,但它不起作用。

Even if the attribute in JSON is not present, the field is receiving a default value.即使 JSON 中的属性不存在,该字段也会接收默认值。

My code:我的代码:

RestController:休息控制器:

import org.springframework.web.bind.annotation.*;


@RestController
@RequestMapping("/api")
public class MyController {

    @PostMapping("/save-data")
    public void saveData( @RequestHeader("my-request-header") String myHeader, @RequestBody MyValueObject myValueObject) {
        service.saveData(myValueObject);
    }

}

POJO: POJO:

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import javax.validation.constraints.NotNull;


@Builder
@Getter
@Setter
@Data
@AllArgsConstructor
public class MyValueObject {

    @JsonProperty(access = JsonProperty.Access.READ_ONLY)
    @NotNull
    private String id;

    @JsonProperty(value = "my_name")
    @NotNull
    private String name;

    @NotNull
    private int age;
}

So if in json request I'm passing only id & name, I'm still getting age as 0(zero).因此,如果在 json 请求中我只传递 id 和 name,我的年龄仍然为 0(零)。

Primitive types do have default value which is what is getting set for age since it is int.原始类型确实具有默认值,因为它是 int,所以设置为年龄。 Can you change it to Integer class.你能把它改成 Integer class。

javax.validation.constraints.NotNull;

The notion of validation is generally what you apply to outside input .验证的概念通常适用于外部输入 You have no control over that input directly;您无法直接控制该输入; hence, the need to validate it before continuing.因此,需要在继续之前对其进行验证。

Crucially, then, it should be possible for an object that models this input to represent invalid state .至关重要的是,object 应该可以模拟这个输入来表示无效的 state After all, invalid input can happen , and your code is supposed to perfectly represent such input.毕竟,可能会发生无效输入,并且您的代码应该完美地代表此类输入。 This input should then be deemed as invalid and rejected once you try to use it.一旦您尝试使用该输入,则该输入应被视为无效并被拒绝。

That means it should be possible to mark something as @NotNull (this particular NotNull annotation, which is specifically about validation, there are others that are not,), and still create an object where the value is null anyway.这意味着应该可以将某些东西标记为@NotNull (这个特殊的 NotNull 注释,专门用于验证,还有其他不是),并且仍然创建一个 object ,其中值是null无论如何。 Such an object is not valid , and a validation framework will know it isn't, based on that annotation.这样的 object is not valid ,并且验证框架会根据该注释知道它不是。

There are other takes on not null annotations.还有其他非 null 注释。 When you are using a class as a 'model' for defining an SQL database table, annotations exist that guide the creation of the CREATE TABLE statement, and one can 'guide': Please add an SQL NOT NULL constraint. When you are using a class as a 'model' for defining an SQL database table, annotations exist that guide the creation of the CREATE TABLE statement, and one can 'guide': Please add an SQL NOT NULL constraint. That's a completely different concept entirely and yet those annotations are also called @NotNull .这完全是一个完全不同的概念,但这些注释也称为@NotNull

A third concept is requesting code injection to inject a null check.第三个概念是请求代码注入以注入 null 检查。 This is what lombok's @NonNull annotation does.这就是 lombok 的@NonNull注释所做的。 If you write:如果你写:

void foo(@lombok.NonNull String hello) {
  System.out.println(hello);
}

then lombok turns that into:然后龙目岛把它变成:

void foo(@lombok.NonNull String hello) {
  if (hello == null) throw new NullPointerException("hello");
  System.out.println(hello);
}

And a fourth, yet again completely different take, is as a type system modifier.第四种,也是完全不同的方式,是作为类型系统修饰符。 The notion 'the parameter to the foo method is a string reference that CANNOT be null. ' foo方法的参数是一个字符串引用,不能是 null。 This take sounds identical to lombok's take, but it is in fact essentially the opposite.这个镜头听起来与龙目岛的镜头相同,但实际上恰恰相反。 This code, is obviously silly and doesn't even compile, it's that silly:这段代码显然很愚蠢,甚至无法编译,就是这么愚蠢:

void foo(String arg) {
  if (arg instanceof Integer) thow new IllegalArgumentException("Please give me a string and not an integer");
}

for the exact same reason, the lombok generated code is 'silly' if you deem that @NonNull to be a type modifier.出于完全相同的原因,如果您认为@NonNull是类型修饰符,则 lombok 生成的代码是“愚蠢的”。 It CANNOT be null as per the type analysis, so why are you checking for an impossibility?根据类型分析,它不能null ,那你为什么要检查不可能呢?

Thus, this is a 4th 'take' and all 4 takes are completely different in what they mean and do .因此,这是第 4 次“拍摄”,所有 4 次拍摄的含义和作用都完全不同 This last one doesn't "work" with vanilla java (which doesn't enforce non-nullity onto callers, the way java does enforce that you eg don't pass an Integer instance to a method like this, and you can't get around this enforcement in any way), but there are compiler plugins and the like that add it, and if you live in a world where all compilation uses these plugins, then the null check is, indeed, warning-to-error-level unneccessary.最后一个不适用于普通 java (它不会对调用者强制执行非无效性,就像 java确实强制您例如不要将Integer和 CB4C06F2B94 之类的实例方法传递给以任何方式绕过这种强制执行),但是有编译器插件等添加它,如果你生活在一个所有编译都使用这些插件的世界,那么 null 检查确实是警告到错误级别不必要的。

To add fuel to this already considerable fire, java supports annotating parameters, fields, and methods.为了火上浇油,java 支持注释参数、字段和方法。 Java also supports annotating types. Java支持注解类型。 Some null annotations operate on p/f/ms, others operate on types, and yet again this causes significant differences in how to use them and what they actually end up causing to happen.一些 null 注释在 p/f/ms 上运行,其他则在类型上运行,这再次导致如何使用它们以及它们最终导致发生的情况存在显着差异。

Given all that, hopefully you now understand why it is 'hard' to make a @NonNull or @NotNull annotation do what you want it to do.鉴于这一切,希望你现在明白为什么让@NonNull@NotNull注释做你想做的事情是“困难的”。 They are all different, and there are like 20 commonly used variants.它们都是不同的,并且有大约 20 种常用的变体。

I noticed in your question you didn't actually properly describe what you want.我注意到你的问题实际上并没有正确描述你想要什么。 Probably because you're not quite aware of all the various takes on what 'not null' can mean.可能是因为您不太了解“非空”可能意味着的所有各种不同的看法。 You can use this answer as a guide so you know precisely what you do want and then read the documentation of the various null-annotation framework(s) you have available to you, and pick the correct one.您可以将此答案用作指南,以便准确了解您想要什么,然后阅读您可以使用的各种空注释框架的文档,然后选择正确的。 Then apply that annotation, and it'll then do what you want it to do.然后应用该注释,然后它将执行您希望它执行的操作。

I want the fields in this object to be not null, that is they should always have non-blank value.我希望此 object 中的字段不是 null,即它们应该始终具有非空白值。

an int cannot be 'blank'. int不能为“空白”。 If you consider '0' to be 'blank', okay, you can of course add a constraint that they must not be 0, but @NonNull or @NotNull , any variant and any of the 20 takes out there on the concept, they'd all NOT do that.如果您认为“0”是“空白”,好吧,您当然可以添加一个约束条件,即它们不能为 0,但是@NonNull@NotNull ,任何变体和 20 中的任何一个都在概念上出现,他们不会那样做。 Because null and 0 are very different things.因为 null 和 0 是非常不同的东西。 Various validation frameworks do have a 'not this specific int value' concept, you can use one of those.各种验证框架确实有一个“不是这个特定的 int 值”的概念,您可以使用其中之一。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM