rethianita / spring-book

Undocumented class found JAVA-D1000
Documentation
Minor
46 occurrences in this check
Consider adding a doc comment for UserService
 22import org.springframework.stereotype.Service;
 23import org.springframework.transaction.annotation.Transactional;
 24
 25@Service 26@Transactional(readOnly = true) 27@RequiredArgsConstructor 28public class UserService implements UserDetailsService { 29 30  private final UserRepo userRepo; 31  private final UserEditMapper userEditMapper; 32  private final UserViewMapper userViewMapper; 33  private final PasswordEncoder passwordEncoder; 34 35  @Transactional 36  public UserView create(CreateUserRequest request) { 37    if (userRepo.findByUsername(request.username()).isPresent()) { 38      throw new ValidationException("Username exists!"); 39    } 40    if (!request.password().equals(request.rePassword())) { 41      throw new ValidationException("Passwords don't match!"); 42    } 43 44    var user = userEditMapper.create(request); 45    user.setPassword(passwordEncoder.encode(request.password())); 46 47    user = userRepo.save(user); 48 49    return userViewMapper.toUserView(user); 50  } 51 52  @Transactional 53  public UserView update(ObjectId id, UpdateUserRequest request) { 54    var user = userRepo.getById(id); 55    userEditMapper.update(request, user); 56 57    user = userRepo.save(user); 58 59    return userViewMapper.toUserView(user); 60  } 61 62  @Transactional 63  public UserView upsert(CreateUserRequest request) { 64    var optionalUser = userRepo.findByUsername(request.username()); 65 66    if (optionalUser.isEmpty()) { 67      return create(request); 68    } else { 69      UpdateUserRequest updateUserRequest = 70          new UpdateUserRequest(request.fullName(), request.authorities()); 71      return update(optionalUser.get().getId(), updateUserRequest); 72    } 73  } 74 75  @Transactional 76  public UserView delete(ObjectId id) { 77    var user = userRepo.getById(id); 78 79    user.setUsername( 80        user.getUsername().replace("@", String.format("_%s@", user.getId().toString()))); 81    user.setEnabled(false); 82    user = userRepo.save(user); 83 84    return userViewMapper.toUserView(user); 85  } 86 87  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 88    return userRepo 89        .findByUsername(username) 90        .orElseThrow( 91            () -> 92                new UsernameNotFoundException( 93                    format("User with username - %s, not found", username))); 94  } 95 96  public boolean usernameExists(String username) { 97    return userRepo.findByUsername(username).isPresent(); 98  } 99100  public UserView getUser(ObjectId id) {101    return userViewMapper.toUserView(userRepo.getById(id));102  }103104  public List<UserView> searchUsers(Page page, SearchUsersQuery query) {105    List<User> users = userRepo.searchUsers(page, query);106    return userViewMapper.toUserView(users);107  }108}
Consider adding a doc comment for BookService
16import org.springframework.transaction.annotation.Transactional;
17import org.springframework.util.CollectionUtils;
18
19@Service20@Transactional(readOnly = true)21@RequiredArgsConstructor22public class BookService {2324  private final BookRepo bookRepo;25  private final AuthorRepo authorRepo;26  private final BookEditMapper bookEditMapper;27  private final BookViewMapper bookViewMapper;2829  @Transactional30  public BookView create(EditBookRequest request) {31    var book = bookEditMapper.create(request);3233    book = bookRepo.save(book);34    updateAuthors(book);3536    return bookViewMapper.toBookView(book);37  }3839  @Transactional40  public BookView update(ObjectId id, EditBookRequest request) {41    var book = bookRepo.getById(id);42    bookEditMapper.update(request, book);4344    book = bookRepo.save(book);45    if (!CollectionUtils.isEmpty(request.authorIds())) {46      updateAuthors(book);47    }4849    return bookViewMapper.toBookView(book);50  }5152  private void updateAuthors(Book book) {53    var authors = authorRepo.findAllById(book.getAuthorIds());54    authors.forEach(author -> author.getBookIds().add(book.getId()));55    authorRepo.saveAll(authors);56  }5758  @Transactional59  public BookView delete(ObjectId id) {60    var book = bookRepo.getById(id);6162    bookRepo.delete(book);6364    return bookViewMapper.toBookView(book);65  }6667  public BookView getBook(ObjectId id) {68    var book = bookRepo.getById(id);69    return bookViewMapper.toBookView(book);70  }7172  public List<BookView> getBooks(Iterable<ObjectId> ids) {73    var books = bookRepo.findAllById(ids);74    return bookViewMapper.toBookView(books);75  }7677  public List<BookView> getAuthorBooks(ObjectId authorId) {78    var author = authorRepo.getById(authorId);79    return bookViewMapper.toBookView(bookRepo.findAllById(author.getBookIds()));80  }8182  public List<BookView> searchBooks(Page page, SearchBooksQuery query) {83    return bookViewMapper.toBookView(bookRepo.searchBooks(page, query));84  }85}
Consider adding a doc comment for AuthorService
14import org.springframework.stereotype.Service;
15import org.springframework.transaction.annotation.Transactional;
16
17@Service18@Transactional(readOnly = true)19@RequiredArgsConstructor20public class AuthorService {2122  private final AuthorRepo authorRepo;23  private final BookRepo bookRepo;24  private final AuthorEditMapper authorEditMapper;25  private final AuthorViewMapper authorViewMapper;2627  @Transactional28  public AuthorView create(EditAuthorRequest request) {29    var author = authorEditMapper.create(request);3031    author = authorRepo.save(author);3233    return authorViewMapper.toAuthorView(author);34  }3536  @Transactional37  public AuthorView update(ObjectId id, EditAuthorRequest request) {38    var author = authorRepo.getById(id);39    authorEditMapper.update(request, author);4041    author = authorRepo.save(author);4243    return authorViewMapper.toAuthorView(author);44  }4546  @Transactional47  public AuthorView delete(ObjectId id) {48    var author = authorRepo.getById(id);4950    authorRepo.delete(author);51    bookRepo.deleteAll(bookRepo.findAllById(author.getBookIds()));5253    return authorViewMapper.toAuthorView(author);54  }5556  public AuthorView getAuthor(ObjectId id) {57    return authorViewMapper.toAuthorView(authorRepo.getById(id));58  }5960  public List<AuthorView> getAuthors(Iterable<ObjectId> ids) {61    return authorViewMapper.toAuthorView(authorRepo.findAllById(ids));62  }6364  public List<AuthorView> getBookAuthors(ObjectId bookId) {65    var book = bookRepo.getById(bookId);66    return authorViewMapper.toAuthorView(authorRepo.findAllById(book.getAuthorIds()));67  }6869  public List<AuthorView> searchAuthors(Page page, SearchAuthorsQuery query) {70    return authorViewMapper.toAuthorView(authorRepo.searchAuthors(page, query));71  }72}
Consider adding a doc comment for UserRepoCustom
 60  Optional<User> findByUsername(String username);
 61}
 62
 63interface UserRepoCustom { 64 65  List<User> searchUsers(Page page, SearchUsersQuery query); 66} 67
 68@RequiredArgsConstructor
 69class UserRepoCustomImpl implements UserRepoCustom {
Consider adding a doc comment for UserRepoCustomImpl
 65  List<User> searchUsers(Page page, SearchUsersQuery query);
 66}
 67
 68@RequiredArgsConstructor 69class UserRepoCustomImpl implements UserRepoCustom { 70 71  private final MongoTemplate mongoTemplate; 72 73  @Override 74  public List<User> searchUsers(Page page, SearchUsersQuery query) { 75    var operations = new ArrayList<AggregationOperation>(); 76 77    var criteriaList = new ArrayList<Criteria>(); 78    if (StringUtils.hasText(query.id())) { 79      criteriaList.add(Criteria.where("id").is(new ObjectId(query.id()))); 80    } 81    if (StringUtils.hasText(query.username())) { 82      criteriaList.add(Criteria.where("username").regex(query.username(), "i")); 83    } 84    if (StringUtils.hasText(query.fullName())) { 85      criteriaList.add(Criteria.where("fullName").regex(query.fullName(), "i")); 86    } 87    if (!criteriaList.isEmpty()) { 88      Criteria userCriteria = new Criteria().andOperator(criteriaList.toArray(new Criteria[0])); 89      operations.add(match(userCriteria)); 90    } 91 92    operations.add(sort(Sort.Direction.DESC, "createdAt")); 93    operations.add(skip((page.number() - 1) * page.limit())); 94    operations.add(limit(page.limit())); 95 96    var aggregation = newAggregation(User.class, operations); 97    var results = mongoTemplate.aggregate(aggregation, User.class); 98    return results.getMappedResults(); 99  }100}
Consider adding a doc comment for UserRepo
 27import org.springframework.stereotype.Repository;
 28import org.springframework.util.StringUtils;
 29
 30@Repository 31@CacheConfig(cacheNames = "users") 32public interface UserRepo extends UserRepoCustom, MongoRepository<User, ObjectId> { 33 34  @CacheEvict(allEntries = true) 35  <S extends User> List<S> saveAll(Iterable<S> entities); 36 37  @Caching( 38      evict = { 39        @CacheEvict(key = "#p0.id", condition = "#p0.id != null"), 40        @CacheEvict(key = "#p0.username", condition = "#p0.username != null") 41      }) 42  <S extends User> S save(S entity); 43 44  @Cacheable 45  Optional<User> findById(ObjectId objectId); 46 47  @Cacheable 48  default User getById(ObjectId id) { 49    var optionalUser = findById(id); 50    if (optionalUser.isEmpty()) { 51      throw new NotFoundException(User.class, id); 52    } 53    if (!optionalUser.get().isEnabled()) { 54      throw new NotFoundException(User.class, id); 55    } 56    return optionalUser.get(); 57  } 58 59  @Cacheable 60  Optional<User> findByUsername(String username); 61} 62
 63interface UserRepoCustom {
 64
Consider adding a doc comment for BookRepoCustom
 35  List<Book> findAllById(Iterable<ObjectId> ids);
 36}
 37
 38interface BookRepoCustom { 39 40  List<Book> searchBooks(Page page, SearchBooksQuery query); 41} 42
 43@RequiredArgsConstructor
 44class BookRepoCustomImpl implements BookRepoCustom {
Consider adding a doc comment for BookRepoCustomImpl
 40  List<Book> searchBooks(Page page, SearchBooksQuery query);
 41}
 42
 43@RequiredArgsConstructor 44class BookRepoCustomImpl implements BookRepoCustom { 45 46  private final MongoTemplate mongoTemplate; 47 48  @Override 49  public List<Book> searchBooks(Page page, SearchBooksQuery query) { 50    var operations = new ArrayList<AggregationOperation>(); 51 52    var criteriaList = new ArrayList<Criteria>(); 53    if (StringUtils.hasText(query.id())) { 54      criteriaList.add(Criteria.where("id").is(new ObjectId(query.id()))); 55    } 56    if (StringUtils.hasText(query.creatorId())) { 57      criteriaList.add(Criteria.where("creatorId").is(new ObjectId(query.creatorId()))); 58    } 59    if (query.createdAtStart() != null) { 60      criteriaList.add(Criteria.where("createdAt").gte(query.createdAtStart())); 61    } 62    if (query.createdAtEnd() != null) { 63      criteriaList.add(Criteria.where("createdAt").lt(query.createdAtEnd())); 64    } 65    if (StringUtils.hasText(query.title())) { 66      criteriaList.add(Criteria.where("title").regex(query.title(), "i")); 67    } 68    if (!CollectionUtils.isEmpty(query.genres())) { 69      criteriaList.add(Criteria.where("genres").all(query.genres())); 70    } 71    if (StringUtils.hasText(query.isbn13())) { 72      criteriaList.add(Criteria.where("isbn13").is(query.isbn13())); 73    } 74    if (StringUtils.hasText(query.isbn10())) { 75      criteriaList.add(Criteria.where("isbn10").is(query.isbn10())); 76    } 77    if (StringUtils.hasText(query.publisher())) { 78      criteriaList.add(Criteria.where("publisher").regex(query.publisher(), "i")); 79    } 80    if (query.publishDateStart() != null) { 81      criteriaList.add(Criteria.where("publishDate").gte(query.publishDateStart())); 82    } 83    if (query.publishDateEnd() != null) { 84      criteriaList.add(Criteria.where("publishDate").lt(query.publishDateEnd())); 85    } 86    if (!criteriaList.isEmpty()) { 87      var bookCriteria = new Criteria().andOperator(criteriaList.toArray(new Criteria[0])); 88      operations.add(match(bookCriteria)); 89    } 90 91    criteriaList = new ArrayList<Criteria>(); 92    if (StringUtils.hasText(query.authorId())) { 93      criteriaList.add(Criteria.where("author._id").is(new ObjectId(query.authorId()))); 94    } 95    if (StringUtils.hasText(query.authorFullName())) { 96      criteriaList.add(Criteria.where("author.fullName").regex(query.authorFullName(), "i")); 97    } 98    if (!criteriaList.isEmpty()) { 99      var authorCriteria = new Criteria().andOperator(criteriaList.toArray(new Criteria[0]));100      operations.add(lookup("authors", "authorIds", "_id", "author"));101      operations.add(unwind("author", false));102      operations.add(match(authorCriteria));103    }104105    operations.add(sort(Sort.Direction.DESC, "createdAt"));106    operations.add(skip((page.number() - 1) * page.limit()));107    operations.add(limit(page.limit()));108109    var aggregation = newAggregation(Book.class, operations);110    var results = mongoTemplate.aggregate(aggregation, Book.class);111    return results.getMappedResults();112  }113}
Consider adding a doc comment for BookRepo
 25import org.springframework.util.CollectionUtils;
 26import org.springframework.util.StringUtils;
 27
 28@Repository 29public interface BookRepo extends MongoRepository<Book, ObjectId>, BookRepoCustom { 30 31  default Book getById(ObjectId id) { 32    return findById(id).orElseThrow(() -> new NotFoundException(Book.class, id)); 33  } 34 35  List<Book> findAllById(Iterable<ObjectId> ids); 36} 37
 38interface BookRepoCustom {
 39
Consider adding a doc comment for AuthorRepoCustom
35  List<Author> findAllById(Iterable<ObjectId> ids);
36}
37
38interface AuthorRepoCustom {3940  List<Author> searchAuthors(Page page, SearchAuthorsQuery query);41}42
43@RequiredArgsConstructor
44class AuthorRepoCustomImpl implements AuthorRepoCustom {
Consider adding a doc comment for AuthorRepo
25import org.springframework.util.CollectionUtils;
26import org.springframework.util.StringUtils;
27
28@Repository29public interface AuthorRepo extends MongoRepository<Author, ObjectId>, AuthorRepoCustom {3031  default Author getById(ObjectId id) {32    return findById(id).orElseThrow(() -> new NotFoundException(Author.class, id));33  }3435  List<Author> findAllById(Iterable<ObjectId> ids);36}37
38interface AuthorRepoCustom {
39
Consider adding a doc comment for AuthorRepoCustomImpl
40  List<Author> searchAuthors(Page page, SearchAuthorsQuery query);
41}
42
43@RequiredArgsConstructor44class AuthorRepoCustomImpl implements AuthorRepoCustom {4546  private final MongoTemplate mongoTemplate;4748  @Override49  public List<Author> searchAuthors(Page page, SearchAuthorsQuery query) {50    var operations = new ArrayList<AggregationOperation>();5152    var criteriaList = new ArrayList<Criteria>();53    if (StringUtils.hasText(query.id())) {54      criteriaList.add(Criteria.where("id").is(new ObjectId(query.id())));55    }56    if (StringUtils.hasText(query.creatorId())) {57      criteriaList.add(Criteria.where("creatorId").is(new ObjectId(query.creatorId())));58    }59    if (query.createdAtStart() != null) {60      criteriaList.add(Criteria.where("createdAt").gte(query.createdAtStart()));61    }62    if (query.createdAtEnd() != null) {63      criteriaList.add(Criteria.where("createdAt").lt(query.createdAtEnd()));64    }65    if (StringUtils.hasText(query.fullName())) {66      criteriaList.add(Criteria.where("fullName").regex(query.fullName(), "i"));67    }68    if (!CollectionUtils.isEmpty(query.genres())) {69      criteriaList.add(Criteria.where("genres").all(query.genres()));70    }71    if (!criteriaList.isEmpty()) {72      var authorCriteria = new Criteria().andOperator(criteriaList.toArray(new Criteria[0]));73      operations.add(match(authorCriteria));74    }7576    criteriaList = new ArrayList<Criteria>();77    if (StringUtils.hasText(query.bookId())) {78      criteriaList.add(Criteria.where("book._id").is(new ObjectId(query.bookId())));79    }80    if (StringUtils.hasText(query.bookTitle())) {81      criteriaList.add(Criteria.where("book.title").regex(query.bookTitle(), "i"));82    }83    if (!criteriaList.isEmpty()) {84      var bookCriteria = new Criteria().andOperator(criteriaList.toArray(new Criteria[0]));85      operations.add(lookup("books", "bookIds", "_id", "book"));86      operations.add(unwind("book", false));87      operations.add(match(bookCriteria));88    }8990    operations.add(sort(Sort.Direction.DESC, "createdAt"));91    operations.add(skip((page.number() - 1) * page.limit()));92    operations.add(limit(page.limit()));9394    var aggregation = newAggregation(Author.class, operations);95    var results = mongoTemplate.aggregate(aggregation, Author.class);96    return results.getMappedResults();97  }98}
Consider adding a doc comment for User
14import java.util.HashSet;
15import java.util.Set;
16
17@Document(collection = "users")18@Getter @Setter19public class User extends ComparableEntity implements UserDetails {2021  @Id22  private ObjectId id;2324  @CreatedDate25  private LocalDateTime createdAt;26  @LastModifiedDate27  private LocalDateTime modifiedAt;2829  private boolean enabled = true;3031  @Indexed(unique = true)32  private String username;33  private String password;34  @Indexed35  private String fullName;36  private Set<Role> authorities = new HashSet<>();3738  public User() {39  }4041  public User(String username, String password) {42    this.username = username;43    this.password = password;44  }4546  @Override47  public boolean isAccountNonExpired() {48    return enabled;49  }5051  @Override52  public boolean isAccountNonLocked() {53    return enabled;54  }5556  @Override57  public boolean isCredentialsNonExpired() {58    return enabled;59  }60}
Consider adding a doc comment for Role
 5import lombok.NoArgsConstructor;
 6import org.springframework.security.core.GrantedAuthority;
 7
 8@Data 9@AllArgsConstructor10@NoArgsConstructor11public class Role implements GrantedAuthority {1213  public static final String USER_ADMIN = "USER_ADMIN";14  public static final String AUTHOR_ADMIN = "AUTHOR_ADMIN";15  public static final String BOOK_ADMIN = "BOOK_ADMIN";1617  private String authority;1819}
Consider adding a doc comment for ComparableEntity
 4
 5import java.io.Serializable;
 6
 7public abstract class ComparableEntity implements Serializable { 8 9  public abstract ObjectId getId();1011  @Override12  public boolean equals(Object o) {13    if (this == o) {14      return true;15    }16    if (o == null || this.getClass() != o.getClass()) {17      return false;18    }19    ComparableEntity that = (ComparableEntity) o;20    return getId().equals(that.getId());21  }2223  @Override24  public int hashCode() {25    return getId().hashCode();26  }27}
Consider adding a doc comment for Book
15import java.util.HashSet;
16import java.util.Set;
17
18@Document(collection = "books")19@Getter @Setter20public class Book extends ComparableEntity {2122  @Id23  private ObjectId id;2425  @CreatedBy26  private ObjectId creatorId;27  @LastModifiedBy28  private ObjectId modifierId;2930  @CreatedDate31  private LocalDateTime createdAt;32  @LastModifiedDate33  private LocalDateTime modifiedAt;3435  private String title;36  private String about;37  private String language;38  private Set<String> genres = new HashSet<>();39  private String isbn13;40  private String isbn10;41  private String publisher;42  private LocalDate publishDate;43  private int hardcover;4445  private Set<ObjectId> authorIds = new HashSet<>();4647}
Consider adding a doc comment for Author
14import java.util.HashSet;
15import java.util.Set;
16
17@Document(collection = "authors")18@Getter @Setter19public class Author extends ComparableEntity {2021  @Id22  private ObjectId id;2324  @CreatedBy25  private ObjectId creatorId;26  @LastModifiedBy27  private ObjectId modifierId;2829  @CreatedDate30  private LocalDateTime createdAt;31  @LastModifiedDate32  private LocalDateTime modifiedAt;3334  private String fullName;35  private String about;36  private String nationality;37  private Set<String> genres = new HashSet<>();3839  private Set<ObjectId> bookIds = new HashSet<>();4041}
Consider adding a doc comment for UserViewMapper
 9
10import java.util.List;
11
12@Mapper(componentModel = "spring", uses = {ObjectIdMapper.class})13public abstract class UserViewMapper {1415  @Autowired16  private UserRepo userRepo;1718  public abstract UserView toUserView(User user);1920  public abstract List<UserView> toUserView(List<User> users);2122  public UserView toUserViewById(ObjectId id) {23    if (id == null) {24      return null;25    }26    return toUserView(userRepo.getById(id));27  }2829}
Consider adding a doc comment for UserEditMapper
17import static org.mapstruct.NullValueCheckStrategy.ALWAYS;
18import static org.mapstruct.NullValuePropertyMappingStrategy.IGNORE;
19
20@Mapper(componentModel = "spring", uses = ObjectIdMapper.class)21public abstract class UserEditMapper {2223  @Mapping(source = "authorities", target = "authorities", qualifiedByName = "stringToRole")24  public abstract User create(CreateUserRequest request);2526  @BeanMapping(nullValueCheckStrategy = ALWAYS, nullValuePropertyMappingStrategy = IGNORE)27  @Mapping(source = "authorities", target = "authorities", qualifiedByName = "stringToRole")28  public abstract void update(UpdateUserRequest request, @MappingTarget User user);2930  @Named("stringToRole")31  protected Set<Role> stringToRole(Set<String> authorities) {32    if (authorities != null) {33      return authorities.stream().map(Role::new).collect(toSet());34    }35    return new HashSet<>();36  }3738}
Consider adding a doc comment for ObjectIdMapper
 3import org.bson.types.ObjectId;
 4import org.mapstruct.Mapper;
 5
 6@Mapper(componentModel = "spring") 7public class ObjectIdMapper { 8 9  public String objectIdToString(ObjectId objectId) {10    return objectId.toString();11  }1213  public ObjectId stringToObjectId(String string) {14    return new ObjectId(string);15  }1617}
Consider adding a doc comment for BookViewMapper
11
12import java.util.List;
13
14@Mapper(componentModel = "spring", uses = ObjectIdMapper.class)15public abstract class BookViewMapper {1617  private UserViewMapper userViewMapper;1819  @Autowired20  public void setUserViewMapper(UserViewMapper userViewMapper) {21    this.userViewMapper = userViewMapper;22  }2324  @Mapping(source = "creatorId", target = "creator", qualifiedByName = "idToUserView")25  public abstract BookView toBookView(Book book);2627  public abstract List<BookView> toBookView(List<Book> books);2829  @Named("idToUserView")30  protected UserView idToUserView(ObjectId id) {31    return userViewMapper.toUserViewById(id);32  }33}
Consider adding a doc comment for BookEditMapper
 9import static org.mapstruct.NullValueCheckStrategy.ALWAYS;
10import static org.mapstruct.NullValuePropertyMappingStrategy.IGNORE;
11
12@Mapper(componentModel = "spring", uses = ObjectIdMapper.class)13public interface BookEditMapper {1415  Book create(EditBookRequest request);1617  @BeanMapping(nullValueCheckStrategy = ALWAYS, nullValuePropertyMappingStrategy = IGNORE)18  void update(EditBookRequest request, @MappingTarget Book book);1920}
Consider adding a doc comment for AuthorViewMapper
11
12import java.util.List;
13
14@Mapper(componentModel = "spring", uses = ObjectIdMapper.class)15public abstract class AuthorViewMapper {1617  private UserViewMapper userViewMapper;1819  @Autowired20  public void setUserViewMapper(UserViewMapper userViewMapper) {21    this.userViewMapper = userViewMapper;22  }2324  @Mapping(source = "creatorId", target = "creator", qualifiedByName = "idToUserView")25  public abstract AuthorView toAuthorView(Author author);2627  public abstract List<AuthorView> toAuthorView(List<Author> authors);2829  @Named("idToUserView")30  protected UserView idToUserView(ObjectId id) {31    return userViewMapper.toUserViewById(id);32  }33}
Consider adding a doc comment for AuthorEditMapper
 9import static org.mapstruct.NullValueCheckStrategy.ALWAYS;
10import static org.mapstruct.NullValuePropertyMappingStrategy.IGNORE;
11
12@Mapper(componentModel = "spring", uses = ObjectIdMapper.class)13public interface AuthorEditMapper {1415  Author create(EditAuthorRequest request);1617  @BeanMapping(nullValueCheckStrategy = ALWAYS, nullValuePropertyMappingStrategy = IGNORE)18  void update(EditAuthorRequest request, @MappingTarget Author author);1920}
Consider adding a doc comment for NotFoundException
 2
 3import org.bson.types.ObjectId;
 4
 5public class NotFoundException extends RuntimeException { 6 7  public NotFoundException(String message) { 8    super(message); 9  }1011  public NotFoundException(Class<?> clazz, long id) {12    super(String.format("Entity %s with id %d not found", clazz.getSimpleName(), id));13  }1415  public NotFoundException(Class<?> clazz, String id) {16    super(String.format("Entity %s with id %s not found", clazz.getSimpleName(), id));17  }1819  public NotFoundException(Class<?> clazz, ObjectId id) {20    super(String.format("Entity %s with id %s not found", clazz.getSimpleName(), id.toString()));21  }2223}