Spring Rest Docs unable to add Model constraints in request fiels table - spring

I want to use the Contraints of my Dto model in my request fields documentation. When I use auto rest docs it works but then I have a problem with my KeycloakAuthMock. So I won't use auto rest docs as per documentation the requestfields can easily be added.
#Test
#Order(5)
#WithMockKeycloakAuth(authorities = "ROLE_owner")
void createProduct_RealmRoleOwner_HttpStatusCreated() throws Exception {
MvcResult response = mockMvc.perform(post(URL).contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(testProductDto))
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.created").isNumber())
.andExpect(jsonPath("$.name").value(testProductDto.getName()))
.andExpect(jsonPath("$.price").value(testProductDto.getPrice()))
.andExpect(jsonPath("$.id").value(1L))
.andDo(document("{methodName}",
Preprocessors.preprocessRequest(),
Preprocessors.preprocessResponse(
ResponseModifyingPreprocessors.replaceBinaryContent(),
ResponseModifyingPreprocessors.limitJsonArrayLength(objectMapper),
Preprocessors.prettyPrint()),
requestFields( fieldWithPath("name").description("Name of the product"),
fieldWithPath("price").description("Price of the new product")),
responseFields(fieldWithPath("id").description("Id of the new product"),
fieldWithPath("name").description("Name of the product"),
fieldWithPath("price").description("Price of the new product"),
fieldWithPath("created").description("Unix timestamp when the product was created")
)))
.andReturn();
Model:
#ApiModel(description = "Data transfer model for a new product.")
public class ProductDto {
#ApiModelProperty(notes = "Name of the new product.")
#NotNull(message = "name must not be null")
#Size(min = 2, max = 10 , message = "Name length min is 2 and max is 10")
private String name;
#ApiModelProperty(notes = "price of the new product")
#NotNull(message = "price must not be null")
#Min(value = 1, message = "price min is 1")
#Max(value = 100, message = "price max is 100")
private Double price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() { return price; }
public void setPrice(Double price) { this.price = price; }
}
I tried to follow the guide and I added the template. The template is used but I get a Mustache exception that contraints field is not found. As I won't document the constraints by hand who can I make spring rest docs add the constraints provided by my model?

Related

OpenApi Swagger not showing Exception as a response

I'm using OpenApi Swagger UI (v. 4.14) with SpringBoot. I'm getting all the info I need with the Swagger, except for the exception. Here's my code.
Garage class:
#Schema(description = "Details about the Car")
#Document("Garage")
public class Garage implements Serializable {
#Schema(description = "An ID of the car in the database", accessMode = Schema.AccessMode.READ_ONLY)
#Id
private String id;
#Schema(description = "The name of the car")
#Field("model")
protected String carModel;
#Schema(description = "Car's engine power output")
protected Integer hp;
#Schema(description = "Production year of the car")
#Field("Year")
protected Integer year;
#Schema(description = "The name of car's designer")
protected String designer;
// controllers, getters, setters, toString
Controller:
// some other code
#Operation(summary = "Deletes a car by its id")
#ApiResponses(value = {
#ApiResponse(responseCode = "200",
description = "A car is deleted from the Garage",
content = {#Content(
schema = #Schema(implementation = Garage.class),
mediaType = "application/json")}),
#ApiResponse(responseCode = "404",
description = "A car with this id is not in our garage",
content = #Content(
schema = #Schema(implementation = RestExceptionHandler.class),
mediaType = "application/json"))})
#DeleteMapping(path = "/deleteCar/{carId}")
public void deleteCarFromGarage(#PathVariable("carId") String id) {
garageService.deleteFromGarage(id);
}
// some other code
Exception handler:
#Schema(description = "Exception handling")
#RestControllerAdvice
public class RestExceptionHandler {
#Schema(description = "The ID is not valid")
#ExceptionHandler(value = {IllegalArgumentException.class})
public ResponseEntity<Object> resourceNotFoundException(IllegalArgumentException exception) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(exception.getMessage());
}
}
I'm getting 200 responses every time, no matter do I delete a correct id, or an incorrect one.
EDIT: here's my deleteFromGarage method
public void deleteFromGarage(String id) {
garageRepository.deleteById(id);
}
I've edited my deleteFromGarage method, and that solved the issue
deleteFromGarage before:
public void deleteFromGarage(String id) {
garageRepository.deleteById(id);
}
deleteFromGarage now:
public void deleteFromGarage(String id) {
if (garageRepository.findById(id).isEmpty()) {
throw new IllegalArgumentException("The ID is not valid");
} else {
garageRepository.deleteById(id);
}
}

better way to POST multipart files with JSON data springboot

I am working on a spring boot project, I have a customer model which consists of properties, including image paths which I am storing in the file system or folder and uploading the entire form with image paths in DB, I have successfully implemented my target task however I was wondering if there is a better and nicer way to achieve this, your answers, comments, and feedbacks are appreciated here is my code
Customer model:
public class Customer {
private String contactMode = "Mobile Number";
#Pattern(regexp ="(251|0)[0-9]{9}" , message = "Invalid phone number")
private String phoneNumber; // phone number
private String identityType = "101-ID [0]";
#NotNull(message = "ID number is required")
private String idNumber;
private String countryOfIssue = "XXXXXXX";
#NotNull(message = "Issue date is required")
#PastOrPresent(message = "Issue date cannot be future date")
private Date issueDate;
#Future(message = "Expiry date cannot be in the past or present")
#NotNull(message = "Expiry date is required")
private Date expiryDate;
// storing customerImage , customerID and customerSignature paths in DB
private String customerImage;
private String customerID;
private String customerSignature;
}
Customer Service:
private String path = "C:\Users\User\Desktop\docs\uploaded_files\";
public Customer saveCustomer(Customer customer, MultipartFile customerImage, MultipartFile customerID,
MultipartFile customerSignature) throws Exception {
final String PATH = path + customer.getContactDetail();
Customer phoneNumberExists = customerRepository.findByContactDetail(customer.getContactDetail());
byte[] imageBytes = customerImage.getBytes();
byte[] idBytes = customerID.getBytes();
byte[] signatureBytes = customerSignature.getBytes();
Path customerImagePath = Paths.get
(PATH + "_photo_" + customerImage.getOriginalFilename());
Files.write(customerImagePath, imageBytes);
Path customerIDPath =
Paths.get(PATH + "_ID_" + customerID.getOriginalFilename());
Files.write(customerIDPath, idBytes);
Path customerSignaturePath =
Paths.get(PATH + "_Sign_" + customerSignature.getOriginalFilename() + "");
Files.write(customerSignaturePath, signatureBytes);
if (phoneNumberExists != null) {
throw new PhoneNumberTakenException("Phone number is taken ");
}
customer.setAge(new Date().getYear() - customer.getDateOfBirth().getYear());
customer.setCustomerImage(String.valueOf(customerImagePath));
customer.setCustomerID(String.valueOf(customerIDPath));
customer.setCustomerSignature(String.valueOf(customerSignaturePath));
customer.setFromDate(LocalDate.now());
customer.setStatus(Customer.Status.Submitted);
Customer customerRecord = customerRepository.saveAndFlush(customer);
return customerRecord;
}
Customer Controller : look at how iam passing multipart files and other fields in the controller to service
#PostMapping()
public ResponseEntity<Customer> createCustomer(#Valid #RequestPart("customer") String customer, MultipartFile customerImage, MultipartFile customerID, MultipartFile customerSignature
) throws Exception {
ObjectMapper customerMapper = new ObjectMapper();
Customer savedCustomer = customerMapper.readValue(customer, Customer.class);
Customer customerRecord = customerService.saveCustomer(savedCustomer, customerImage, customerID, customerSignature);
log.debug("inside createCustomer() controller : {}", customerRecord);
return ResponseEntity.status(HttpStatus.CREATED).body(customerRecord);
}
Postman post request to the endpoint:
Postman response :

Expose enums with Spring Data REST

I'm using Spring Boot 1.5.3, Spring Data REST, HATEOAS.
I've a simple entity model:
#Entity
public class User extends AbstractEntity implements UserDetails {
private static final long serialVersionUID = 5745401123028683585L;
public static final PasswordEncoder PASSWORD_ENCODER = new BCryptPasswordEncoder();
#NotNull(message = "The name of the user cannot be blank")
#Column(nullable = false)
private String name;
/** CONTACT INFORMATION **/
private String landlinePhone;
private String mobilePhone;
#NotNull(message = "The username cannot be blank")
#Column(nullable = false, unique = true)
private String username;
#Email(message = "The email address is not valid")
private String email;
#JsonIgnore
private String password;
#Column(nullable = false)
private String timeZone = "Europe/Rome";
#JsonIgnore
private LocalDateTime lastPasswordResetDate;
#Column(nullable = false, columnDefinition = "BOOLEAN default true")
private boolean enabled = true;
#Type(type = "json")
#Column(columnDefinition = "json")
private Roles[] roles = new Roles[] {};
and my enum Roles is:
public enum Roles {
ROLE_ADMIN, ROLE_USER, ROLE_MANAGER, ROLE_TECH;
#JsonCreator
public static Roles create(String value) {
if (value == null) {
throw new IllegalArgumentException();
}
for (Roles v : values()) {
if (value.equals(v.toString())) {
return v;
}
}
throw new IllegalArgumentException();
}
}
I'm creating a client in Angular 4. Spring Data REST is great and expose repository easily return my model HATEOAS compliant:
{
"_embedded": {
"users": [
{
"name": "Administrator",
"username": "admin",
"roles": [
"Amministratore"
],
"activeWorkSession": "",
"_links": {
"self": {
"href": "http://localhost:8080/api/v1/users/1"
},
"user": {
"href": "http://localhost:8080/api/v1/users/1{?projection}",
"templated": true
}
}
},
Like you can see I'm also translating via rest-messages.properties the value of my enums. Great!
My Angular page now needs the complete lists of roles (enums). I've some question:
understand the better way for the server to return the list of roles
how to return this list
My first attemp was to create a RepositoryRestController in order to take advantage of what Spring Data REST offers.
#RepositoryRestController
#RequestMapping(path = "/api/v1")
public class UserController {
#Autowired
private EntityLinks entityLinks;
#RequestMapping(method = RequestMethod.GET, path = "/users/roles", produces = "application/json")
public Resource<Roles> findRoles() {
Resource<Roles> resource = new Resource<>(Roles.ROLE_ADMIN);
return resource;
}
Unfortunately, for some reason, the call to this methods return a 404 error. I debugged and the resource is created correctly, so I guess the problem is somewhere in the JSON conversion.
how to return this list?
#RepositoryRestController
#RequestMapping("/roles")
public class RoleController {
#GetMapping
public ResponseEntity<?> getAllRoles() {
List<Resource<Roles>> content = new ArrayList<>();
content.addAll(Arrays.asList(
new Resource<>(Roles.ROLE1 /*, Optional Links */),
new Resource<>(Roles.ROLE2 /*, Optional Links */)));
return ResponseEntity.ok(new Resources<>(content /*, Optional Links */));
}
}
I was playing around with this and have found a couple of ways to do it.
Assume you have a front end form that wants to display a combo box containing priorities for a single Todo such as High, Medium, Low. The form needs to know the primary key or id which is the enum value in this instance and the value should be the readable formatted value the combo box should display.
If you wish to customize the json response in 1 place only such as a single endpoint then I found this useful. The secret sauce is using the value object PriorityValue to allow you to rename the json field through #Relation.
public enum Priority {
HIGH("High"),
NORMAL("Normal"),
LOW("Low");
private final String description;
Priority(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public static List<Priority> orderedValues = new ArrayList<>();
static {
orderedValues.addAll(Arrays.asList(Priority.values()));
}
}
#RepositoryRestController
#RequestMapping(value="/")
public class PriorityController {
#Relation(collectionRelation = "priorities")
#JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
private class PriorityValue {
private String id;
private String value;
public PriorityValue(String id,
String value) {
this.id = id;
this.value = value;
}
}
#GetMapping(value = "/api/priorities", produces = MediaTypes.HAL_JSON_VALUE)
public ResponseEntity<Resources<PriorityValue>> getPriorities() {
List<PriorityValue> priorities = Priority.orderedValues.stream()
.map(p -> new PriorityValue(p.name(), p.getDescription()))
.collect(Collectors.toList());
Resources<PriorityValue> resources = new Resources<>(priorities);
resources.add(linkTo(methodOn(PriorityController.class).getPriorities()).withSelfRel());
return ResponseEntity.ok(resources);
}
}
Another approach is to use a custom JsonSerializer. The only issue using this is everywhere a Priority enum is serialized you will end up using this format which may not be what you want.
#JsonSerialize(using = PrioritySerializer.class)
#Relation(collectionRelation = "priorities")
public enum Priority {
HIGH("High"),
NORMAL("Normal"),
LOW("Low");
private final String description;
Priority(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public static List<Priority> orderedValues = new ArrayList<>();
static {
orderedValues.addAll(Arrays.asList(Priority.values()));
}
}
#RepositoryRestController
#RequestMapping(value="/api")
public class PriorityController {
#GetMapping(value = "/priorities", produces = MediaTypes.HAL_JSON_VALUE)
public ResponseEntity<Resources<Priority>> getPriorities() {
Resources<Priority> resources = new Resources<>(Priority.orderedValues);
resources.add(linkTo(methodOn(PriorityController.class).getPriorities()).withSelfRel());
return ResponseEntity.ok(resources);
}
}
public class PrioritySerializer extends JsonSerializer<Priority> {
#Override
public void serialize(Priority priority,
JsonGenerator generator,
SerializerProvider serializerProvider)
throws IOException, JsonProcessingException {
generator.writeStartObject();
generator.writeFieldName("id");
generator.writeString(priority.name());
generator.writeFieldName("value");
generator.writeString(priority.getDescription());
generator.writeEndObject();
}
}
The final json response from http://localhost:8080/api/priorities
{
"_embedded": {
"priorities": [
{
"id": "HIGH",
"value": "High"
},
{
"id": "NORMAL",
"value": "Normal"
},
{
"id": "LOW",
"value": "Low"
}
]
},
"_links": {
"self": {
"href": "http://localhost:8080/api/priorities"
}
}
}

Java: GroupSequenceProvider for Validation, object is null in getValidationGroups method

This is what I am trying to achieve:
I have an update request object and user is allowed to do Partial Updates. But I want to validate the field only if it is in the request body. Otherwise, it is OK to be null. To achieve this, I am using GroupSequenceProvider to let the Validator know what groups to validate. What am I doing wrong here? If there is a blunder, how do I fix it?
Documentation: https://docs.jboss.org/hibernate/validator/5.1/reference/en-US/html/chapter-groups.html#example-implementing-using-default-group-sequence-provider
#GroupSequenceProvider(UpdateUserRegistrationGroupSequenceProvider.class)
public class UpdateUserRegistrationRequestV1 {
#NotBlank(groups = {EmailExistsInRequest.class})
#Email(groups = {EmailExistsInRequest.class})
#SafeHtml(whitelistType = SafeHtml.WhiteListType.NONE, groups = {EmailExistsInRequest.class})
private String email;
#NotNull(groups = {PasswordExistsInRequest.class})
#Size(min = 8, max = 255, groups = {PasswordExistsInRequest.class})
private String password;
#NotNull(groups = {FirstNameExistsInRequest.class})
#Size(max = 255, groups = {FirstNameExistsInRequest.class})
#SafeHtml(whitelistType = SafeHtml.WhiteListType.NONE, groups = {FirstNameExistsInRequest.class})
private String firstName;
// THERE ARE GETTERS AND SETTERS BELOW
}
Group Sequence Provider Code:
public class UpdateUserRegistrationGroupSequenceProvider implements DefaultGroupSequenceProvider<UpdateUserRegistrationRequestV1> {
public interface EmailExistsInRequest {}
public interface PasswordExistsInRequest {}
public interface FirstNameExistsInRequest {}
#Override
public List<Class<?>> getValidationGroups(UpdateUserRegistrationRequestV1 updateUserRegistrationRequestV1) {
List<Class<?>> defaultGroupSequence = new ArrayList<Class<?>>();
defaultGroupSequence.add(Default.class);
defaultGroupSequence.add(UpdateUserRegistrationRequestV1.class);
if(StringUtils.hasText(updateUserRegistrationRequestV1.getEmail())) {
defaultGroupSequence.add(EmailExistsInRequest.class);
}
if(StringUtils.hasText(updateUserRegistrationRequestV1.getPassword())) {
defaultGroupSequence.add(PasswordExistsInRequest.class);
}
if(StringUtils.hasText(updateUserRegistrationRequestV1.getFirstName())) {
defaultGroupSequence.add(FirstNameExistsInRequest.class);
}
return defaultGroupSequence;
}
}
I am using Spring MVC, so this is how my controller method looks,
#RequestMapping(value = "/{userId}", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.NO_CONTENT)
public void updateUser(#PathVariable("userId") Long userId,
#RequestBody #Valid UpdateUserRegistrationRequestV1 request) {
logger.info("Received update request = " + request + " for userId = " + userId);
registrationService.updateUser(userId, conversionService.convert(request, User.class));
}
Now the problem is, the parameter "updateUserRegistrationRequestV1" in the UpdateUserRegistrationGroupSequenceProvider.getValidationGroups method is null. This is the request object that I am sending in the request body and I am sending email field with it.
What am I doing wrong?
I too went through the same issue ,and hopefully solved it
You just have to check the object is null and put all your conditions inside it.
public List<Class<?>> getValidationGroups(Employee object) {
List<Class<?>> sequence = new ArrayList<>();
//first check if the object is null
if(object != null ){
if (!object.isDraft()) {
sequence.add(Second.class);
}
}
// Apply all validation rules from default group
sequence.add(Employee.class);
return sequence;
}

GWT 2.5 + Spring 3 + Hibernate 3 clear example

I saw questions about GWT + SPRING + HIBERNATE integration but none is clear or up to date with the current versions!
Please if there is anyone who has a clear and simple example of the integration (form submit and saving in DB) I will be extremely thankful!
If you could put the simple project in a ZIP and upload it (with its jars it will be great)
Thank you!
I guess this one using gwt 2.5.0-rc1, Spring 3.1.2.RELEASE and Hibernate 4 will be helpful. This project is using maven, so install maven which will take care of required dependencies. git clone it, command-line build with $ mvn clean install and dive into.
The basic gwt server-shared-client architecture is
Entity
#Entity
#Table(name = "TBL_BOOK")
public class Book implements Serializable {
private static final long serialVersionUID = -687874117917352477L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private Long id;
#Column(name = "TITLE", nullable = false)
private String title;
#Column(name = "SUBTITLE")
private String subtitle;
#Column(name = "AUTOR", nullable = false)
private String autor;
#Column(name = "DESCRIPTION")
private String description;
#Column(name = "ISBN")
private String isbn;
#Column(name = "GENRE")
private String genre;
#Temporal(TemporalType.DATE)
#Column(name = "PUBLISHED_DATE")
private Date publishedDate;
#Column(name = "PUBLISHER")
private String publisher;
public Book() {
}
public Book(Long id, String title, String subtitle, String autor,
String description, String isbn, String genre, Date publishedDate,
String publisher) {
this.id = id;
this.title = title;
this.subtitle = subtitle;
this.autor = autor;
this.description = description;
this.isbn = isbn;
this.genre = genre;
this.publishedDate = publishedDate;
this.publisher = publisher;
}
public Book(Book bookDTO) {
this.id = bookDTO.getId();
this.title = bookDTO.getTitle();
this.subtitle = bookDTO.getSubtitle();
this.autor = bookDTO.getAutor();
this.description = bookDTO.getDescription();
this.isbn = bookDTO.getIsbn();
this.genre = bookDTO.getGenre();
this.publishedDate = bookDTO.getPublishedDate();
this.publisher = bookDTO.getPublisher();
}
//getters and setters
#Override
public String toString() {
return "Book [id=" + id + ", title=" + title + ", subtitle=" + subtitle
+ ", author=" + autor + ", description=" + description
+ ", isbn=" + isbn + ", genre=" + genre + ", publishedDate="
+ publishedDate + ", publisher=" + publisher + "]";
}
}
web configuration
<!-- SpringGwt remote service servlet -->
<servlet>
<servlet-name>springGwtRemoteServiceServlet</servlet-name>
<servlet-class>org.spring4gwt.server.SpringGwtRemoteServiceServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springGwtRemoteServiceServlet</servlet-name>
<url-pattern>/GwtSpringHibernate/springGwtServices/*</url-pattern>
</servlet-mapping>
Client side stub for RPC
/**
* The client side stub for the RPC service.
*/
#RemoteServiceRelativePath("springGwtServices/bookService")
public interface BookService extends RemoteService {
public void saveOrUpdate(Book book) throws Exception;
public void delete(Book book) throws Exception;
public Book find(long id);
public List<Book> findAllEntries();
}
Server
#Service("bookService")
public class BookServiceImpl extends RemoteServiceServlet implements BookService {
private static final long serialVersionUID = -6547737229424190373L;
private static final Log LOG = LogFactory.getLog(BookServiceImpl.class);
#Autowired
private BookDAO bookDAO;
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void saveOrUpdate(Book book) throws Exception {
//
}
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void delete(Book book) throws Exception {
//
}
public Book find(long id) {
return bookDAO.findById(id);
}
public List<Book> findAllEntries() {
//
}
}
Client View
/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class GwtSpringHibernate implements EntryPoint {
/**
* The message displayed to the user when the server cannot be reached or
* returns an error.
*/
private static final String SERVER_ERROR = "An error occurred while "
+ "attempting to contact the server. Please check your network "
+ "connection and try again.";
/**
* Create a remote service proxy to talk to the server-side Book service.
*/
private final BookServiceAsync bookService = GWT.create(BookService.class);
/**
* This is the entry point method.
*/
public void onModuleLoad() {
DateBox.DefaultFormat defaultFormatter = new DateBox.DefaultFormat(DateTimeFormat.getFormat("dd.MM.yyyy"));
// Add new Book Area
final TextBox titleField = new TextBox();
titleField.setFocus(true);
final TextBox subtitleField = new TextBox();
final TextBox autorField = new TextBox();
final TextBox descriptionField = new TextBox();
final TextBox isbnField = new TextBox();
final TextBox genreField = new TextBox();
final DateBox publishedDateField = new DateBox();
publishedDateField.setFormat(defaultFormatter);
final TextBox publisherField = new TextBox();
final Button saveButton = new Button("Save");
saveButton.addStyleName("button");
final Button retrieveButton = new Button("Retrieve");
retrieveButton.addStyleName("button");
final Label errorLabel = new Label();
// Add fields to the Rootpanel
RootPanel.get("title").add(titleField);
RootPanel.get("subtitle").add(subtitleField);
RootPanel.get("autor").add(autorField);
RootPanel.get("description").add(descriptionField);
RootPanel.get("isbn").add(isbnField);
RootPanel.get("genre").add(genreField);
RootPanel.get("publishedDate").add(publishedDateField);
RootPanel.get("publisher").add(publisherField);
RootPanel.get("btnSave").add(saveButton);
RootPanel.get("btnRetrieveAllEntries").add(retrieveButton);
RootPanel.get("errorLabelContainer").add(errorLabel);
// Create the popup dialog box
final DialogBox dialogBox = new DialogBox();
dialogBox.setText("Remote Procedure Call");
dialogBox.setAnimationEnabled(true);
final Button closeButton = new Button("Close");
// We can set the id of a widget by accessing its Element
closeButton.getElement().setId("closeButton");
final Label textToServerLabel = new Label();
final HTML serverResponseLabel = new HTML();
VerticalPanel dialogVPanel = new VerticalPanel();
dialogVPanel.addStyleName("dialogVPanel");
dialogVPanel.add(new HTML("<b>Sending request to the server:</b>"));
dialogVPanel.add(textToServerLabel);
dialogVPanel.add(new HTML("<b>Server replies:</b>"));
dialogVPanel.add(serverResponseLabel);
dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);
dialogVPanel.add(closeButton);
dialogBox.setWidget(dialogVPanel);
// Add a handler to close the DialogBox
closeButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
dialogBox.hide();
saveButton.setEnabled(true);
saveButton.setFocus(true);
retrieveButton.setEnabled(true);
}
});
class SaveBookHandler implements ClickHandler, KeyUpHandler {
public void onKeyUp(KeyUpEvent event) {
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
saveBook();
}
}
public void onClick(ClickEvent arg0) {
saveBook();
}
private void saveBook() {
errorLabel.setText("");
String _title = titleField.getText();
String _subtitle = subtitleField.getText();
String _autor = autorField.getText();
String _desc = descriptionField.getText();
String _isbn = isbnField.getText();
String _genre = genreField.getText();
Date _publishedDate = publishedDateField.getValue();
String _publisher = publisherField.getText();
// First, we validate the input.
if (Validator.isBlank(_title) || Validator.isBlank(_autor)) {
String errorMessage = "Please enter at least the Title and the Autor of the book";
errorLabel.setText(errorMessage);
return;
}
Book bookDTO = new Book(null, _title, _subtitle, _autor, _desc, _isbn, _genre, _publishedDate, _publisher);
saveButton.setEnabled(false);
serverResponseLabel.setText("");
textToServerLabel.setText(bookDTO.toString());
bookService.saveOrUpdate(bookDTO, new AsyncCallback<Void>() {
public void onFailure(Throwable caught) {
dialogBox.setText("Remote Procedure Call - Failure");
serverResponseLabel.addStyleName("serverResponseLabelError");
serverResponseLabel.setHTML(SERVER_ERROR + caught.toString());
dialogBox.center();
closeButton.setFocus(true);
}
public void onSuccess(Void noAnswer) {
dialogBox.setText("Remote Procedure Call");
serverResponseLabel.removeStyleName("serverResponseLabelError");
serverResponseLabel.setHTML("OK");
dialogBox.center();
closeButton.setFocus(true);
}
});
}
}
// Add a handler to send the book info to the server
SaveBookHandler saveBookHandler = new SaveBookHandler();
saveButton.addClickHandler(saveBookHandler);
publisherField.addKeyUpHandler(saveBookHandler);
// Create a handler for the retrieveButton
class RetrieveAllEntriesHandler implements ClickHandler {
/**
* Fired when the user clicks on the retrieveButton.
*/
public void onClick(ClickEvent event) {
retrieveAllEntries();
}
private void retrieveAllEntries() {
// Nothing to validate here
// Then, we send the input to the server.
retrieveButton.setEnabled(false);
errorLabel.setText("");
textToServerLabel.setText("");
serverResponseLabel.setText("");
bookService.findAllEntries(
new AsyncCallback<List<Book>>() {
public void onFailure(Throwable caught) {
// Show the RPC error message to the user
dialogBox.setText("Remote Procedure Call - Failure");
serverResponseLabel.addStyleName("serverResponseLabelError");
serverResponseLabel.setHTML(SERVER_ERROR + caught.toString());
dialogBox.center();
closeButton.setFocus(true);
}
public void onSuccess(List<Book> data) {
dialogBox.setText("Remote Procedure Call");
serverResponseLabel.removeStyleName("serverResponseLabelError");
if(data != null && !data.isEmpty()){
StringBuffer buffer = new StringBuffer();
for (Book book : data) {
buffer.append(book.toString());
buffer.append("<br /><br />");
}
serverResponseLabel.setHTML(buffer.toString());
} else {
serverResponseLabel.setHTML("No book information store in the database.");
}
dialogBox.center();
closeButton.setFocus(true);
}
});
}
}
// Add a handler
RetrieveAllEntriesHandler retrieveAllEntriesHandler = new RetrieveAllEntriesHandler();
retrieveButton.addClickHandler(retrieveAllEntriesHandler);
}
}
For more widgets, go through official widget library, UiBinder.
1) Download the zip file cited above from https://github.com/chieukam/gwt-spring-hibernate-tutorial/archive/master.zip and extract it somewhere
2) In Eclipse, create a new Maven project. Since there is no .project file provided in the above zip, you will need to confiugre all this manually.
3) Import "File System" from the place where you unzipped this project into your new Maven project.
At this point, I have some errors:
BookServiceAsync appears to be nonexistent, resulting in 6 compile errors.
"Plugin execution not covered by lifecycle configuration: org.apache.maven.plugins:maven-war-plugin:2.1.1:exploded (execution: default, phase: compile)" in pom.xml, lines 162 and 185
This example seems to be somewhat incomplete. Am I missing something??

Resources