swagger springfox - bean validation JSR 303 not recognize - spring

I followed this tutorial https://springframework.guru/spring-boot-restful-api-documentation-with-swagger-2/ to generate a swagger documentation.
It's working but when I try to add some validation in my bean I don't find the information in the documentation:
#ApiOperation(value = "Creates a product",
notes="Populates a product instance bla bla")
#RequestMapping(value = "/add", method = RequestMethod.POST, produces = "application/json")
public ResponseEntity saveProduct( #Valid #RequestBody Product product){
productService.saveProduct(product);
return new ResponseEntity("Product saved successfully", HttpStatus.OK);
}
My entity with the validations annotations :
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
// #ApiModelProperty(notes = "The database generated product ID")
private Integer id;
#Version
// #ApiModelProperty(notes = "The auto-generated version of the product")
#NotNull
private Integer version;
// #ApiModelProperty(notes = "The application-specific product ID" )
private String productId;
// #ApiModelProperty(notes = "The product description")
#NotBlank
#Size(max = 50)
private String description;
// #ApiModelProperty(notes = "The image URL of the product")
private String imageUrl;
// #ApiModelProperty(notes = "The price of the product", required = true)
#NotNull
private BigDecimal price;
But when I check the documentation I don't have those validation information:
Here https://github.com/springfox/springfox/issues/987 they say that we need to update our dependencies and it's what I did :
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
</dependency>
Did I miss something in the configuration? Any idea to help me ?

I found the solution in this post : http://vojtechruzicka.com/documenting-spring-boot-rest-api-swagger-springfox/.
All is explained :
Unfortunately, JSR-303 based documentation does not work out of the box, you need an additional dependency:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-bean-validators</artifactId>
<version>2.8.0</version>
</dependency>
And you need to import BeanValidatorPluginsConfiguration configuration file on top of your swagger configuration class:
#Configuration
#EnableSwagger2
#Import(BeanValidatorPluginsConfiguration.class)
public class SpringFoxConfig {
...
}
Thank you #vojtech-ruzicka https://stackoverflow.com/users/4560142/vojtech-ruzicka

Related

Why lombok do not create the setters and getters?

I am new to Spring Boot framework and lombok.
I defined my entity like that:
#Entity
#Table(name = "student")
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
public class Student implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String firstName;
private String lastName;
private String email;
}
I also create a controller where I add the following:
#PostMapping(path="/add") // Map ONLY POST Requests
public #ResponseBody String addNewUser (#RequestParam String name
, #RequestParam String email) {
// #ResponseBody means the returned String is the response, not a view name
// #RequestParam means it is a parameter from the GET or POST request
Student st = new Student();
st.setFirstName(name);
st.setEmail(email);
//studentservice.save(st);
return "Saved";
}
I dont know why I have a red line under setFirstName. They ask me to create this function in the student class.
I am using eclipse.
please follow the steps as below:
check pom.xml for lombok dependency
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
Now you can check your IDE,
I hope, it helps!

Quarkus Reactive with Vert.x and Hibernate Reactive / java.lang.NullPointerException: Cannot store to object array because "this.loadedState" is null

i am trying to use quarkus reactive with vert.x and hibernate reactive.
this is my pom.xml:
<quarkus-plugin.version>1.12.2.Final</quarkus-plugin.version>
and
<quarkus.platform.version>1.12.2.Final</quarkus.platform.version>
with:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-reactive-mysql-client</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-vertx-web</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-reactive</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-reactive-pg-client</artifactId>
</dependency>
this is my application.properties file:
# postgres-configuration
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=partner_usr
quarkus.datasource.password=postgrespw
quarkus.datasource.reactive.url=vertx-reactive:postgres://localhost:3310/partnerdb
# test, but not working (schema's won't created)
quarkus.hibernate-orm.database.generation.create-schemas=true
# working (drop-and-create only on mysql, not on postgres)
quarkus.hibernate-orm.database.generation=drop-and-create
quarkus.hibernate-orm.log.sql=true
quarkus.http.cors=true
Then, i have following entities:
#Data
#MappedSuperclass
public abstract class IdEntity {
#Id
#SequenceGenerator(name = "entitySeq", sequenceName = "entitiy_id", allocationSize = 1, initialValue = 5)
#GeneratedValue(generator = "entitySeq", strategy = GenerationType.AUTO)
private Long id;
}
#Data
#Entity
#EqualsAndHashCode(callSuper = true)
public class Person extends IdEntity {
private String firstName;
private String lastName;
public Person() {
}
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Address personAddress;
}
#Data
#Entity
#EqualsAndHashCode(callSuper = true)
public class Address extends IdEntity {
private String street;
private String houseNumber;
private int postalCode;
private String city;
#OneToMany(orphanRemoval = true, mappedBy = "personAddress", fetch = FetchType.LAZY)
private List<Person> persons = new ArrayList<>();
public Address() {
}
}
Now, i am calling a reactive web-service with a reactive db access:
#Path("/person")
#ApplicationScoped
public class PersonResource {
#Inject
io.vertx.mutiny.pgclient.PgPool sqlClient;
#Inject
Mutiny.Session mutinySession;
#GET
//#Produces(MediaType.APPLICATION_JSON)
#Path("/list-persons")
#Route(path = "/list-persons", methods = HttpMethod.GET, produces = MediaType.APPLICATION_JSON)
#Transactional
public Multi<Person> listAllPersons() {
// return sqlClient.query("SELECT * FROM Person ORDER BY lastName ASC").execute()
// .onItem().transformToMulti(set -> Multi.createFrom().iterable(set))
// .onItem().transform(this::transformPersons);
return mutinySession.createQuery("SELECT f FROM Person f ORDER BY f.lastName")
.getResults().onItem().transform(this::transformObject);
}
private Person transformObject(Object f) {
return (Person)f;
}
private List<Object> transformPersons(Object f) {
final Person person = (PartnerMockEntity)f;
final List<Object> bogus = new ArrayList<>();
bogus.add(partner);
return bogus;
}
}
Exception:
Resulted in: com.fasterxml.jackson.databind.JsonMappingException: Cannot store to object array because "this.loadedState" is null (through reference chain: de.subito.model.Person["personAddress"]->de.subito.model.Address["person"])
I tried to use :
FetchType.EAGER on Address in Person
I removed the #OneToMany Relation in Address: this solves the error (yay), but the addresses won't be returned in the resulting json (id is existing, but the values are not fetched)
The questions is, how can i fetch in reactive those kind of relations without getting errors?
Or do i need a angular page in order to display this correctly?
Somehow i forgot about how fetchType.Lazy works.
Simply add a join fetch into the hql and everything works as expected.
SELECT p from Person p left join fetch p.personAddress
When using this query, there's no session/closed or any other exception thrown and the json result will be displayed as expected.
Additional note: in order to avoid recursive serialization, it is required to use the
#JsonManagedReference and #JsonBackReference
Annotations, depending on your needs to your relations.

#NotNull #NotBlank #Valid is not working in spring boot rest api validation

#NotNull, #NotEmpty, #NotBlank annotations are not working in my rest controller. My requirement is to restrict the flow at controller and get 400 error when i hit the controller without required parameters. But when i pass null or empty headers to my controller, i am not getting 400 error. my controller hits my handler class which is not the expected behaviour
Below is my controller
#RestController
#RequestMapping("/intelligent-banking")
public class CrossSellOffersRetrievalController {
#Autowired
private CrossSellOffersRetrievalHandler crossSellOffersRetrievalHandler;
#Autowired
Environment env;
#GetMapping(value = "/cross-sell-offers/{interactionPoint}", produces = { MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<CrossSellOffersRetrievalResponse> getApplicableOffers(
#RequestHeader(value = "channelId", required = true) #Valid String channelId,
#RequestHeader(value = "clientId", required = false) String clientId,
#RequestHeader(value = "actionId", required = true) #NotNull #NotEmpty String actionId,
#RequestHeader(value = "customerId", required = true) #NotNull #NotBlank String customerId,
#RequestHeader(value = "cinSuffix", required = true) #NotNull #NotBlank String cinSuffix,
#RequestHeader(value = "sessionId", required = true) #NotNull #NotBlank String sessionId,
#RequestHeader(value = "countryCode", required = true) #NotNull #NotBlank String countryCode,
#PathVariable(value = "interactionPoint", required = true) #NotNull #NotBlank String interactionPoint,
#RequestParam(value = "numberOfOffers", required = false) Integer numberOfOffers)
throws CrossSellOffersException {
try {
CrossSellOffersRetrievalResponse crossSellOffersResponse = crossSellOffersRetrievalHandler.getCrossSellOffersRetrievalResponse(channelId,
customerId, cinSuffix, countryCode, interactionPoint, sessionId, numberOfOffers);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("CustomerId", customerId);
return new ResponseEntity<>(crossSellOffersResponse, httpHeaders, HttpStatus.OK);
}
catch (Exception e) {
LOGGER.error("Inside CrossSellOffersRetrievalController::getApplicableOffers::Exception - Exception occurred at getApplicableOffers: {} ",e.getMessage());
throw new CrossSellOffersException(Constants.ERROR_CODE, e.getMessage());
}
}
}
You need to enable validation for both request parameters and path variables via adding #Validated annotation to your controller in order for validations to be executed.
Use this maven dependency inorder make those work
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.3.2.RELEASE</version>
</dependency>
was using This dependency of validation in spring boot and didn't work ,due to version upgrade of spring boot to 2.4.0
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
Replaced it with spring-boot-starter-validation and it worked .
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-
starter-validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.4.0</version>
</dependency>
**Need to enable validation for both request parameters and path variables via adding #Validated annotation to your controller in order for validations to be executed.**

getOutputStream() has already been called for this response when fill data in child table with spring boot

I am using spring boot 1.5.10 & spring rest to develop some rest services
I have relation one to many between product and services.
When I fill data in services table and access the service that get me all products(http://localhost:8080/user/products) give me this exception:
Caused by: java.lang.IllegalStateException: getOutputStream() has
already been called for this response.
and repeated json appear in the browser!
If services table is empty: no exception is thrown. I don't know why.
I found a link that discuss the problem but yet I couldn't solve it.
Product entity:
#Entity
#Table(name = "products")
public class Product implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ID")
private Integer id;
#Basic(optional = false)
#Column(name = "NAME")
private String name;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "productId")
private List<Service> servicesList;
}
Service Entity:
#Entity
#Table(name = "services")
public class Service implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ID")
private Integer id;
#Basic(optional = false)
#Column(name = "NAME")
private String name;
#Basic(optional = false)
#Column(name = "TYPE")
private int type;
#JoinColumn(name = "PRODUCT_ID", referencedColumnName = "ID")
#ManyToOne(optional = false)
private Product productId;
}
And the ProductController
#Controller
#RequestMapping("user")
#CrossOrigin(origins="http://localhost:4200", allowedHeaders="*")
public class ProductController {
#Autowired
private IProductService productService;
#GetMapping("product/{id}")
public ResponseEntity<Product> getProductById(#PathVariable("id") Integer id) {
Product product = productService.getProductById(id);
return new ResponseEntity<Product>(product, HttpStatus.OK);
}
#GetMapping("products")
public ResponseEntity<List<Product>> getAllProducts() {
List<Product> list = productService.getAllProducts();
return new ResponseEntity<List<Product>>(list, HttpStatus.OK);
}
}
pom.xml is defined as follows.
http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
<groupId>com.app</groupId>
<artifactId>Assignment</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Assignment</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
As discussed in the link you have shared, you need to create a response class to be sent to the client who is calling the API.
For example, you might have a class saying ProductResponse which might look like this.
public class ProductResponse implements Serializable {
public Integer id;
public String name;
public List<Service> servicesList;
}
Now in the controller class, populate create the response as follows.
#GetMapping("product/{id}")
public ResponseEntity<ProductResponse> getProductById(#PathVariable("id") Integer id) {
Product product = productService.getProductById(id);
ProductResponse productResponse = createProductResponse(product);
return new ResponseEntity<ProductResponse>(productResponse, HttpStatus.OK);
}
ProductResponse createProductResponse(Product product) {
ProductResponse productResponse = new ProductResponse();
productResponse.id = product.id;
productResponse.name = product.name;
productResponse.serviceList = product.serviceList;
}
And yes, you need to specify the FetchType.EAGER in the entity class of Product.
#Entity
#Table(name = "products")
public class Product implements Serializable {
// ... Other parameters
#OneToMany(fetch = "FetchType.EAGER", cascade = CascadeType.ALL, mappedBy = "productId")
private List<Service> servicesList;
}
Hope that helps.

cassandra-driver-mapping: InvalidTypeException: Invalid 32-bits float value, expecting 4 bytes but got 6

As I got issues with spring-data-cassandra with docker as describer here I switched to use com.datastax.cassandra library for cassandra operations but I am getting issues while mapping the resulted object using entity mapper as per this link
Here is my code ...
public String getUser(String userName) {
Mapper<User> mapper = manager.mapper(User.class);
User result = mapper.get(userName); // no issue getting User
String accountNum = result.getAccountId();
return accountNum ;
}
public Account getAccount(String accountNum){
Mapper<Account> mapper = manager.mapper(Account.class);
Account account = mapper.get(accountNum); // getting error here
return account;
}
Account.java
#Table(name = "account")
public class Account {
#PartitionKey
private String accountNum;
private String accountsubtype;
private float currentbalance;
private String customertype;
private String firstname;
private boolean isactive;
private String payments;
private String status;
....
//Getters & Setters
}
pom.xml dependecies
<dependency>
<groupId>com.datastax.cassandra</groupId>
<artifactId>cassandra-driver-core</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>com.datastax.cassandra</groupId>
<artifactId>cassandra-driver-mapping</artifactId>
<version>3.0.0</version>
</dependency>

Resources