Reputation: 113
I'm refactoring some controller tests implementing dto instead of the db entity and now ran into this problem. I don't know how but it throws an exception when trying to instantiate the orikaMapperFacade Bean.
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean
with name 'orikaMapperFacade' defined in class path resource
[net/rakugakibox/spring/boot/orika/OrikaAutoConfiguration.class]: Bean instantiation via
factory method failed; nested exception is
org.springframework.beans.BeanInstantiationException: Failed to instantiate
[ma.glasnost.orika.MapperFacade]: Factory method 'orikaMapperFacade' threw exception;
nested exception is java.lang.reflect.InaccessibleObjectException: Unable to make
protected native java.lang.Object java.lang.Object.clone() throws
java.lang.CloneNotSupportedException accessible: module java.base does not "opens
java.lang" to unnamed module @67b64c45
So this is the controller tests class:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = BooksApplication.class)
@AutoConfigureMockMvc
class BookControllerTests {
@Autowired
MockMvc mockMvc;
@Autowired
ObjectMapper mapper;
@MockBean
BookController bookController;
@Autowired
private BookConverter converter;
@Test
public void createBook_success() throws Exception {
Book book = Book.builder().name("Great book").build();
BookDto dto = converter.toDto(book);
given(bookController.createBook(dto)).willReturn(dto);
mockMvc.perform(post("/api/books/")
.contentType(MediaType.APPLICATION_JSON).content(asJsonString(book)))
.andExpect(status().isCreated());
}
@Test
public void getAllBooks_success() throws Exception {
Book book1 = Book.builder().name("New book").author("Ivan").build();
Book book2 = Book.builder().name("This book").author("Whatever").build();
List<Book> bookList = new ArrayList<>(Arrays.asList(book1, book2));
//bookRepository.save(book);
Mockito.when(bookController.getAllBooks()).thenReturn(bookList);
mockMvc.perform(MockMvcRequestBuilders.get("/api/books/")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(2)))
.andExpect(jsonPath("$[0].name", is("New book")));
}
@Test
public void findByTitle_success() throws Exception {
Book book = Book.builder().name("New book").author("Ivan").build();
Mockito.when(bookController.findByTitle(book.getName())).thenReturn(book);
LinkedMultiValueMap<String, String> requestParams = new LinkedMultiValueMap<>();
requestParams.add("name", "New book");
mockMvc.perform(MockMvcRequestBuilders.get("/api/books/").params(requestParams)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
private String asJsonString(final Object obj){
try{
return new ObjectMapper().writeValueAsString(obj);
} catch (Exception e){
throw new RuntimeException(e);
}
}
}
This is the POJO:
@Entity
@JsonIgnoreProperties("deleted")
@Table(name="books", uniqueConstraints = {@UniqueConstraint(columnNames = "name")})
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="id")
private Integer id;
@Column(name="name")
private String name;
@Column(name="author")
private String author;
@Column(name="publication_year")
@JsonFormat (shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private LocalDate publicationYear;
@Column(name="pages_number")
private int pagesNumber;
@Column(name="publisher")
private String publisher;
@Column(name="is_deleted")
private Boolean isDeleted;
public void setId(Integer id) {this.id = id;}
public Integer getId() {return id;}
public void setName(String name) {this.name = name;}
public String getName() {return name;}
public void setAuthor(String author) {this.author = author;}
public String getAuthor() {return author;}
public void setPublicationYear(LocalDate publicationYear) {this.publicationYear =
publicationYear;}
public LocalDate getPublicationYear() {return publicationYear;}
public void setPagesNumber(int pagesNumber) {this.pagesNumber = pagesNumber;}
public int getPagesNumber() {return pagesNumber;}
public void setPublisher(String publisher) {this.publisher = publisher;}
public String getPublisher() {return publisher;}
public void setDeleted(Boolean deleted) {isDeleted = deleted;}
public Boolean getDeleted() {return isDeleted;}
}
This is the DTO:
public class BookDto {
@NotNull(message = "Name of the book cannot be empty!")
@Size(min = 4, max = 30, message = "Name of the book must be between 4 and 30 characters
long!")
public String name;
@NotNull(message = "Author of the book cannot be empty!")
@Size(min = 5, max = 35, message = "Author of the book must be between 5 and 35
characters long!")
public String author;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
public String publicationYear;
@NotNull(message = "Pages of the book cannot be null!")
@Digits(integer = 4, fraction = 0)
public int pagesNum;
@NotNull(message = "Publisher of the book cannot be empty!")
@Size(min = 4, max = 30, message = "Publisher of the book must be between 4 and 30
characters long!")
public String publisher;
}
This is mapping configuration:
@Component
public class BookConverter {
private final MapperFacade mapperFacade;
public BookConverter(MapperFacade mapperFacade) {
this.mapperFacade = mapperFacade;
}
public MapperFacade getMapperFacade(){
return mapperFacade;
}
public BookDto toDto(Book entity){
return mapperFacade.map(entity, BookDto.class);
}
public Book fromDto(BookDto dto){
return mapperFacade.map(dto, Book.class);
}
}
public class BookMapper extends CustomMapper<Book, BookDto> {
@Override
public void mapBtoA(BookDto bookDto, Book book, MappingContext
context) {
super.mapBtoA(bookDto, book, context);
}
}
public class MappingConfig implements OrikaMapperFactoryConfigurer{
@Override
public void configure(MapperFactory orikaMapperFactory) {
orikaMapperFactory.classMap(Book.class, BookDto.class)
.customize(new BookMapper())
.byDefault()
.register();
orikaMapperFactory.classMap(Book.class, BookDto.class)
.byDefault()
.register();
}
}
This is pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.krylosov_books</groupId>
<artifactId>books</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>books</name>
<description>books</description>
<properties>
<java.version>11</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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<!-- Junit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
<!-- Mockito extension -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>net.rakugakibox.spring.boot</groupId>
<artifactId>orika-spring-boot-starter</artifactId>
<version>1.9.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${project.parent.version}</version>
</plugin>
</plugins>
</build>
</project>
Any help please?
Upvotes: 0
Views: 474