I'm playing around in SpringBoot and i want to count the amount of users in my database.
UserRepository
public interface UserRepository extends JpaRepository<User, Long> {
#Query(value = "select COUNT(*) from user", nativeQuery = true)
Integer findAllActiveUsers();
}
UserService
public Integer amountOfUsersInDB() {
return userRepository.findAllActiveUsers();
}
UserController
#GetMapping("/myusers")
public ResponseEntity amountOfUsers() {
System.out.println(userService.amountOfUsersInDB());
return ResponseEntity.ok(userService.amountOfUsersInDB());
}
When i make the http get call it returns the amount of users inside my database as an Integer. How can i make it return the value as an JSON so i can later on dsplay it on my frontend?
When you have something like this:
#GetMapping(value = "/count", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Integer> getCount() {
Integer count = 1;
return ResponseEntity.ok(count);
}
You'll have the following response payload which, by the way, is a valid JSON:
1
Now, if you want to produce a JSON object, then you could use a Map<String, Object> for representing the payload:
#GetMapping(value = "/count", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Map<String, Object>> getCount() {
Integer count = 1;
Map<String, Object> payload = new HashMap<>();
payload.put("count", count);
return ResponseEntity.ok(payload);
}
Or you could define a class representing the payload, create and instance of such class and assign a value to the count field:
#Data
public class CountPayload {
private Integer count;
}
#GetMapping(value = "/count", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<CountPayload> getCount() {
Integer count = 1;
CountPayload payload = new CountPayload();
payload.setCount(count);
return ResponseEntity.ok(payload);
}
Related
I am learning Spring WebFlux.
My Entity goes like this:
#Table("users")
public class User {
#Id
private Integer id;
private String name;
private int age;
private double salary;
}
I have a Repository (R2 using H2 Database) like below:
public interface UserRepository extends ReactiveCrudRepository<User,Integer> {
}
And my controller is:
#Autowired
private UserRepository userRepository;
private static List<User> userList = new ArrayList<>();
#PostConstruct
public void initializeStockObjects() {
User stock1 = new User(11, "aaaa", 123, 123);
User stock2 = new User(12, "bbb", 123, 123);
User stock3 = new User(13, "ccc", 123, 123);
userList.add(stock1);
userList.add(stock2);
userList.add(stock3);
}
#RequestMapping(value = "/livelistofusers", method = RequestMethod.GET, produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<List<User>> getUsers() {
return getUserData(userList);
}
public Flux<List<User>> getUserData(List<User> userList) {
Flux<Long> interval = Flux.interval(Duration.ofSeconds(3));
interval.subscribe((i) -> userList.forEach(user -> addNewUser(user)));
Flux<List<User>> transactionFlux = Flux.fromStream(Stream.generate(() -> userList));
return Flux.zip(interval, transactionFlux).map(Tuple2::getT2);
}
All good till this point. I am able to return the the entire list of users every 3 seconds to the view. No issues at all here.
Now, I want to send the Flue i.e. Flux flux2 = userRepository.findAll() to the view. That means, instead of return getUserData(userList); how can I do return getUserData(flux2(...what should I do here ???... I tried couple of things but I end up making the Blocking list instead of Non-Blocking ...)); ?
Question: How can I achieve this? i.e. How can I send the entire Flux every 3 seconds to my view. I am feeling lost here and clueless. Any relevant help links or solution will be greatly appreciated.
Edit:
As per Nipuna's comments I tried this:
#RequestMapping(value = "/livelistofusersall", method = RequestMethod.GET, produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<List<User>> getUsersall() {
Flux<Long> interval = Flux.interval(Duration.ofSeconds(3));
interval.subscribe((i) -> userRepository.findAll());
Flux<List<User>> transactionFlux = userRepository.findAll().collectList().flatMapMany(Flux::just);
return Flux.zip(interval, transactionFlux).map(Tuple2::getT2);
}
But now at my context path, the list loads but "only once" after a wait of 3 seconds. What I am missing here?
You can use collectList() operator in Flux for this which gives a Mono of List.
userRepository.findAll().collectList().flatMapMany(Flux::just);
I am trying to figure out mickito test for Named Jdbc Template but unable to do so. I did googling but did not find any accurate result. Below is example Code.
Student.class
#Data
public class Student {
private int id;
private String name;
private String address;
public Student(ResultSet rs) throws SQLException {
id = rs.getInt("id");
name = rs.getString("name");
address = rs.getString("address");
}
}
Student class takes ResultSet argument in constructor and mapped all column to variable .
StudentService.class
public class StudentService {
#Autowired
#Qualifier("namedJdbcTemplate")
NamedParameterJdbcTemplate namedParameterJdbcTemplate;
public Student gerStudent(String id) {
Student student;
String selectStudent = "select id , name ,address from student where id=:id";
MapSqlParameterSource mapSqlParameterSource = new MapSqlParameterSource();
mapSqlParameterSource.addValue(id, "id");
student = namedParameterJdbcTemplate.query(selectStudent, mapSqlParameterSource, resultSet -> {
Student response = new Student(resultSet);
return response;
});
return student;
}
}
Can anyone please help on Mockito Test for below line of code?
student = namedParameterJdbcTemplate.query(selectStudent, mapSqlParameterSource, resultSet -> {
Student response = new Student(resultSet);
return response;
});
I am working on Maven multi module project so this might build error?
I am trying to perform unit test of delete method from controller and I quite don't understand why it is happening here because methods similar to this one works.
Exception speaks for itself - cannot convert int to null. But why there is null value where it looks like curl looks correct?
{"timestamp":"2019-12-16T11:47:35.450+0000","path":"/movie-composite/1","status":500,"error":"Internal Server Error","message":"Optional int parameter 'movieId' is present but cannot be translated into a null value due to being declared as a primitive type. Consider declaring it as object wrapper for the corresponding primitive type."}
Ho mapping looks like:
/**
* Sample usage: curl $HOST:$PORT/movie-composite/1
*
* #param movieId
*/
#ApiOperation(
value = "${api.movie-composite.delete-composite-movie.description}",
notes = "${api.movie-composite.delete-composite-movie.notes}")
#ApiResponses(value = {
#ApiResponse(code = 400, message = "Bad Request, invalid format of the request. See response message for more information."),
#ApiResponse(code = 422, message = "Unprocessable entity, input parameters caused the processing to fails. See response message for more information.")
})
#DeleteMapping(
value = "/movie-composite/{movieId}",
produces = "application/json")
void deleteCompositeMovie(#PathVariable int movieId);
its implementation:
#Override
public void deleteCompositeMovie(int movieId) {
log.debug("deleteCompositeMovie will delete Movie, Reviews, Recommendations belonging to Movie with id: {}", movieId);
movieCompositeIntegration.deleteMovie(movieId);
movieCompositeIntegration.deleteReviews(movieId);
movieCompositeIntegration.deleteRecommendations(movieId);
log.debug("deleteCompositeMovie deleted Movie, Reviews, Recommendations belonging to Movie with id: {}", movieId);
}
And finally test that won't pass:
#Test
void deleteCompositeMovie() {
int given = 1;
deleteAndVerify(given, HttpStatus.OK);
verify(baseMovieCompositeService, times(1)).deleteCompositeMovie(given);
}
where deleteAndVerify(given, HttpStatus.OK) looks like:
private void deleteAndVerify(int id, HttpStatus httpStatus) {
webTestClient.delete()
.uri("/movie-composite/" + id)
.exchange()
.expectStatus().isEqualTo(httpStatus);
}
complete test file looks like:
#ExtendWith(SpringExtension.class)
#SpringBootTest(webEnvironment = RANDOM_PORT)
public class MovieCompositeServiceApplicationTests {
public static final String FAKE_ADDRESS = "Fake address";
public static final String FAKE_GENRE = "Fake genre";
public static final String FAKE_TITLE = "Fake title";
#Autowired
WebTestClient webTestClient;
#MockBean
MovieCompositeIntegration movieCompositeIntegration;
#MockBean
BaseMovieCompositeService baseMovieCompositeService;
#MockBean
ServiceUtil serviceUtil;
#Test
void createMovie() {
int movieId = 1;
MovieAggregate movieAggregate = MovieAggregate.builder()
.movieId(movieId)
.genre(FAKE_GENRE)
.title(FAKE_TITLE)
.recommendations(getRecommendationSummaries())
.reviews(getReviewSummaries())
.serviceAddresses(null)
.build();
postAndVerify(movieAggregate);
}
#Test
void getMovieById() {
int given = 1;
Movie movie = getMovies(given);
Mockito.when(serviceUtil.getServiceAddress()).thenReturn("Fake service address");
List<Recommendation> recommendations = getRecommendations(movie);
List<Review> reviews = getReviews(movie);
Mockito.when(movieCompositeIntegration.getMovie(given)).thenReturn(movie);
Mockito.when(movieCompositeIntegration.getRecommendations(movie.getMovieId())).thenReturn(recommendations);
Mockito.when(movieCompositeIntegration.getReviews(movie.getMovieId())).thenReturn(reviews);
getAndVerifyMovie(given, HttpStatus.OK)
.jsonPath("$.movieId").isEqualTo(given)
.jsonPath("$.recommendations.length()").isEqualTo(3)
.jsonPath("$.reviews.length()").isEqualTo(3);
}
#Test
void getMovieByIdThrowsNotFoundException() {
int given = 1;
Mockito.when(movieCompositeIntegration.getMovie(given)).thenThrow(NotFoundException.class);
getAndVerifyMovie(given, HttpStatus.NOT_FOUND)
.jsonPath("$.path").isEqualTo("/movie-composite/" + given);
}
#Test
void getMovieByIdThrowsInvalidInputException() {
int given = 1;
Mockito.when(movieCompositeIntegration.getMovie(given)).thenThrow(InvalidInputException.class);
getAndVerifyMovie(given, HttpStatus.UNPROCESSABLE_ENTITY)
.jsonPath("$.path").isEqualTo("/movie-composite/" + given);
}
#Test
void deleteCompositeMovie() {
int given = 1;
deleteAndVerify(given, HttpStatus.OK);
verify(baseMovieCompositeService, times(1)).deleteCompositeMovie(given);
}
private WebTestClient.BodyContentSpec getAndVerifyMovie(int id, HttpStatus status) {
return webTestClient.get()
.uri("/movie-composite/" + id)
.accept(MediaType.APPLICATION_JSON_UTF8)
.exchange()
.expectStatus().isEqualTo(status)
.expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)
.expectBody();
}
private WebTestClient.BodyContentSpec postAndVerify(MovieAggregate movieAggregate) {
return webTestClient.post()
.uri("/movie-composite")
.body(just(movieAggregate), MovieAggregate.class)
.exchange()
.expectStatus().isEqualTo(HttpStatus.OK)
.expectBody();
}
private void deleteAndVerify(int id, HttpStatus httpStatus) {
webTestClient.delete()
.uri("/movie-composite/" + id)
.exchange()
.expectStatus().isEqualTo(httpStatus);
}
private List<ReviewSummary> getReviewSummaries() {
return Collections.singletonList(ReviewSummary.builder().reviewId(1).subject("s").author("a").content("c").build());
}
private List<RecommendationSummary> getRecommendationSummaries() {
return Collections.singletonList(RecommendationSummary.builder().recommendationId(1).author("a").content("c").rate(1).build());
}
private Movie getMovies(int given) {
return Movie.builder().movieId(given).address(FAKE_ADDRESS).genre(FAKE_GENRE).title(FAKE_TITLE).build();
}
private List<Review> getReviews(Movie movie) {
return Arrays.asList(
Review.builder().movieId(movie.getMovieId()).reviewId(1).author("Author 1").subject("Subject 1").content("Content 1").serviceAddress(serviceUtil.getServiceAddress()).build(),
Review.builder().movieId(movie.getMovieId()).reviewId(2).author("Author 2").subject("Subject 2").content("Content 2").serviceAddress(serviceUtil.getServiceAddress()).build(),
Review.builder().movieId(movie.getMovieId()).reviewId(3).author("Author 2").subject("Subject 3").content("Content 3").serviceAddress(serviceUtil.getServiceAddress()).build()
);
}
private List<Recommendation> getRecommendations(Movie movie) {
return Arrays.asList(
Recommendation.builder().movieId(movie.getMovieId()).recommendationId(1).author("Author 1").rate(1).content("Content 1").serviceAddress(serviceUtil.getServiceAddress()).build(),
Recommendation.builder().movieId(movie.getMovieId()).recommendationId(2).author("Author 2").rate(2).content("Content 2").serviceAddress(serviceUtil.getServiceAddress()).build(),
Recommendation.builder().movieId(movie.getMovieId()).recommendationId(3).author("Author 3").rate(3).content("Content 3").serviceAddress(serviceUtil.getServiceAddress()).build()
);
}
}
Why it won't pass where getMovieById() looks very similar when it comes to input and url and it passes?
I want to apply paging and sorting to ArrayList of photos. The list is retrived by rest client. Here is my attempt to paging but returns all 5k elements instead. I try to achive a paging like in JpaRepository. The sorting is done by compareTo() method, and doesn't seem to work properly either.
PhotoServiceImpl.java
private List<Photo> repository;
public PhotoServiceImpl() {
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<List<Photo>> photoResponse = restTemplate.exchange("https://jsonplaceholder.typicode.com/photos", HttpMethod.GET, null, new ParameterizedTypeReference<List<Photo>>() {
});
this.repository = photoResponse.getBody();
}
#Override
public List<Photo> findAll() {
return repository;
}
#Override
public Page<Photo> findAll(Pageable pageable) {
List<Photo> photos = findAll();
return new PageImpl<Photo>(photos, new PageRequest(pageable.getPageNumber(), pageable.getPageSize()), photos.size());
}
#Override
public Page<Photo> findAll(Pageable pageable, Sort.Direction sortOrder) {
List<Photo> photos = findAll();
return new PageImpl<Photo>(photos, new
PageRequest(pageable.getPageNumber(), pageable.getPageSize(), sortOrder), photos.size());
}
#Override
public List<Photo> findAll(Sort.Direction sortOrder) {
List<Photo> photos = repository
.stream()
.sorted()
.collect(Collectors.toList());
if (sortOrder.isDescending())
Collections.reverse(photos);
return photos;
}
Photo.java implements Comparable
private int id;
private int albumId;
private String title;
private URL url;
private URL thumbnailUrl;
#Override
public int compareTo(Object o) {
Photo out = ((Photo) o);
int c;
c = Integer.compare(this.getId(), out.getId());
if (c == 0)
c = Integer.compare(this.getAlbumId(), out.getAlbumId());
if (c == 0)
c = this.getTitle().compareTo((out.getTitle()));
return c;
}
}
Getting all photos and the wrapping that in a PageRequest instance with the page size and sorting set will not do what you want. The PageRequest class (or PageImpl class) does not perform the slicing of a list of data into a page or perform the sorting. You must do that yourself
List<Photo> photos = findAll();
//
// << Add your page extraction and sorting code here >>
//
return new PageImpl<Photo>(photos,
new PageRequest(pageable.getPageNumber(), pageable.getPageSize(), sortOrder), photos.size());
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;
}