Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Micronaut Validation documentation incorrect statement about @Introspected #232

Open
sergey-morenets opened this issue Oct 17, 2023 · 1 comment

Comments

@sergey-morenets
Copy link

Expected Behavior

Validation documentation shouldn't state that @introspected annotation is required for validation.

Actual Behaviour

Current Micronaut Validation documentation (https://micronaut-projects.github.io/micronaut-validation/snapshot/guide/) states that:

To validate data classes, e.g. POJOs (typically used in JSON interchange), the class must be annotated with @Introspected (see Micronaut Guide Introspection section) or, if the class is external, be imported by the @introspected annotation.

However that's not true as per Micronaut 4.1.4.

So here's our POJO:

public class Product {

    @NotEmpty
    private String name;

    private int id;

    public String getName() {
        return name;
    }

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

    public int getId() {
        return id;
    }

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

And our configuration class:

@SerdeImport(Product.class)
public class BeanValidationConfiguration {
}

So there's no @introspected here (@SerdeImport is meta-annotation but doesn't contain it) however Jakarta Validation works which was confirmed by our tests.

Steps To Reproduce

No response

Environment Information

No response

Example Application

No response

Version

4.1.4

@nedelva
Copy link

nedelva commented Mar 15, 2024

Suppose we generate a Micronaut application (Java 17+Maven) with the following features: validation, serialization-jackson, lombok, http-client, then add these classes:

package org.acme.model;

import jakarta.validation.constraints.NotEmpty;
import lombok.Data;

@Data
public class Product {
    @NotEmpty
    private String name;

    private int id;
}

We add also a validated controller:

package org.acme;

import io.micronaut.http.annotation.Body;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Post;
import jakarta.validation.Valid;
import org.acme.model.Product;

@Controller("/product")
public class ProductsController {
    @Post
    public String addProduct(@Valid @Body Product product) {
        return String.format("added product %s", product);
    }
}

Start the application with mn:run and issue a POST request in your favorite http client app:

POST http://localhost:8080/product
Content-Type: application/json

{
  "id": 1000, "name": null
}

I have a few remarks:

  1. Without the BeanValidationConfiguration class annotated with @SerdeImport there will be an error stating

" No bean introspection available for type [class org.acme.model.Product]. Ensure the class is annotated with io.micronaut.core.annotation.Introspected""

So fixing the error should be straightforward: annotate the class with @Introspected. Problem is, this time around we get another error:

"Internal Server Error: No deserializable introspection present for type: Product product. Consider adding Serdeable.Deserializable annotate to type Product product. Alternatively if you are not in control of the project's source code, you can use @SerdeImport(Product.class) to enable deserialization of this type."

When we use the annotation Serdeable.Deserializable we get the expected output:

{
  "_links": {
    "self": [
      {
        "href": "/product",
        "templated": false
      }
    ]
  },
  "_embedded": {
    "errors": [
      {
        "message": "product.name: must not be empty"
      }
    ]
  },
  "message": "Bad Request"
}
  1. The last error suggested an alternative to Serdeable.Deserializable, which brings me to the second point, using the @SerdeImport(Product.class) annotation. This is what OP tried and I can confirm that if you use it, no extra annotations are required on Product. This should come as unsurprising though, because the intented usage of @SerdeImport is to introspect external classes (from a library that you do not own @sergey-morenets).

Conclusion

The section 5 of Validation docs is indeed incorrect with respect to point 1 (it should have mentioned @Serdeable.Deserializable instead of @Introspected) and incomplete with respect to point 2 (a quick remark could be added there, that you don't need @Introspected on your own classes if you choose to mark them via @SerdeImport.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants