Hi I'm learning Spring Framework after my Java Core Study. I'm making very simple CRUD MVC application. There is a problem #Transactional annotation doesn't work. Could someone more expierienced in that matter help me? Stack:(Java,Spring,Hibernate,Maven).
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.adrianzaplata</groupId>
<artifactId>hibernate-tutorial</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>hibernate-tutorial Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.27.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-orm -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-c3p0 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>5.4.27.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/jstl/jstl -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
<build>
<finalName>hibernate-tutorial</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
my configuration:
package com.adrianzaplata.project.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import java.beans.PropertyVetoException;
import java.util.Properties;
#Configuration
#EnableWebMvc
#EnableTransactionManagement
#ComponentScan(basePackages = {"com.adrianzaplata.project"})
public class AppConfig {
#Bean
public InternalResourceViewResolver viewResolver()
{
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
#Bean(destroyMethod = "close")
public ComboPooledDataSource comboPooledDataSource() throws PropertyVetoException {
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass("com.mysql.jdbc.Driver");
cpds.setJdbcUrl("jdbc:mysql://localhost:3306/hibernate?useSSL=false");
cpds.setUser("adrian");
cpds.setPassword("chomik12");
cpds.setMinPoolSize(5);
cpds.setMaxPoolSize(20);
cpds.setMaxIdleTime(30000);
return cpds;
}
//
#Bean
public LocalSessionFactoryBean beanFactory() throws PropertyVetoException {
LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
factory.setDataSource(comboPooledDataSource());
factory.setPackagesToScan("com.adrianzaplata.project.entities");
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.dialect","org.hibernate.dialect.MySQLDialect");
hibernateProperties.setProperty("hibernate.show_sql","true");
factory.setHibernateProperties(hibernateProperties);
return factory;
}
#Bean
public PlatformTransactionManager hibernateTransactionManager() throws PropertyVetoException {
HibernateTransactionManager transactionManager
= new HibernateTransactionManager();
transactionManager.setSessionFactory(beanFactory().getObject());
return transactionManager;
}
}
my init class instead of web.xml
package com.adrianzaplata.project.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
#Configuration
public class AppInit extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
Class[] confClasses = {AppConfig.class};
return confClasses;
}
#Override
protected String[] getServletMappings() {
String[] mappings = {"/"};
return mappings;
}
}
Controller
package com.adrianzaplata.project.controllers;
import com.adrianzaplata.project.entities.Customer;
import com.adrianzaplata.project.service.CustomerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
#Controller
#RequestMapping("/customer")
public class CustomerController {
#Autowired
private CustomerService customerService;
#GetMapping("/all")
public String listCustomers(Model model)
{
List<Customer> theCustomers = customerService.getAllCustomers();
model.addAttribute("customers",theCustomers);
return "customer-all";
}
#GetMapping("/showAddForm")
public String addCustomer(#ModelAttribute("CustomerDTO") Customer customerDTO)
{
return "add-customer";
}
#PostMapping("/process-add-form")
public void processCustomer(HttpServletRequest request, HttpServletResponse response, #ModelAttribute("CustomerDTO") Customer customerDTO) throws IOException {
customerService.addCustomer(customerDTO);
response.sendRedirect(request.getContextPath()+"/customer/all");
}
}
At the moment I'm able to read customers from database but method addCustomer doesn't work unless managed transcaction manually inside saveCustomer() method. I suspect that reading customers also does not work by #Transactional annotation.
Service
package com.adrianzaplata.project.service;
import com.adrianzaplata.project.dao.CustomerDao;
import com.adrianzaplata.project.entities.Customer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
#Service
public class CustomerServiceImpl implements CustomerService {
#Autowired
private CustomerDao customerDao;
#Override
#Transactional
public List<Customer> getAllCustomers()
{
return customerDao.getCustomers();
}
#Transactional
#Override
public void addCustomer(Customer customer) {
customerDao.addCustomer(customer);
}
}
DAO
package com.adrianzaplata.project.dao;
import com.adrianzaplata.project.entities.Customer;
import org.hibernate.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public class CustomerDaoImpl implements CustomerDao {
#Autowired
private SessionFactory sessionFactory;
#Override
public List<Customer> getCustomers() {
Session session = sessionFactory.openSession();
try {
SQLQuery query = session.createSQLQuery("SELECT * from customer");
query.addEntity(Customer.class);
List<Customer> customers = query.list();
return customers;
} finally {
session.close();
}
}
#Override
public void addCustomer(Customer customer) {
Session session = sessionFactory.openSession();
session.save(customer);
}
}
I'm just trying to use #Transactional to help me reduce boilerplate code i have to use for hibernate but when i use #Transactional my logic from dao class does not execute. (No queries to database).
Related
I am trying to write a simple 'hello world' application using Spring MVC.
My goal is to send a GET response and receive a text message, however it keeps returning 404 "The requested resource [/api/hello] is not available". What can potentially be wrong? Below is my code:
package org.example.rest.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/api")
public class MyRestController {
#GetMapping("/hello")
public String hello() {
return "Hello";
}
}
Config
package org.example.rest.configuration;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
import java.util.Properties;
#EnableWebMvc
#Configuration
#EnableTransactionManagement
#ComponentScan(basePackages = "org.example.rest")
public class MyConfig {
#Bean
public DataSource dataSource() {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
try {
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/my_db?useSSL=false&serverTimezone=UTC");
dataSource.setUser("bestuser");
dataSource.setPassword("bestuser");
} catch (PropertyVetoException e) {
throw new RuntimeException(e);
}
return dataSource;
}
#Bean
public LocalSessionFactoryBean sessionFactoryBean() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setPackagesToScan("org.example.rest.entity");
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.dialect",
"org.hibernate.dialect.MySQLDialect");
hibernateProperties.setProperty("hibernate.show_sql",
"true");
sessionFactoryBean.setHibernateProperties(hibernateProperties);
return sessionFactoryBean;
}
#Bean
public HibernateTransactionManager hibernateTransactionManager() {
HibernateTransactionManager manager = new HibernateTransactionManager();
manager.setSessionFactory(sessionFactoryBean().getObject());
return manager;
}
}
package org.example.rest.configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class MyWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{MyConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>spring-rest</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.24.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.9</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
I am using IntelliJ IDEA 2022.2.2 (Ultimate Edition).
Server is Tomcat 9.0.71
package com.crudoperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
public class EmployeeController {
#Autowired
private EmployeeService employeeService;
#RequestMapping("/")
public String helloGfg() {
return "hii";
}
#PostMapping("/saveEmployee")
public String saveEmployee(#ModelAttribute("employee") Employee employee) {
employeeService.saveEmployee(employee);
return "redirect:/showEmployee";
}
}
debugger comes in helloGfg method but then it still showing 404 error..i think there will be some other dependency or annotaion based issues......how could i find the issue?below is my pom.xml
<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 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.crudoperation</groupId>
<artifactId>crudoperation</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>crudoperation Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.1.0.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>javax.servlet.jsp.jstl-api</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jasper</artifactId>
<version>8.5.51</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.17.Final</version>
</dependency>
</dependencies>
<build>
<finalName>crudoperation</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
how to find from where the error is coming..in maven project in webapp directory when i seperately run as run on server then it did not even find seprate file..how to solve it?
this is my project structure..which thing i need to remove.i cannot understand.
here is the code for viewResolver
package com.crudoperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Description;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.crudoperation")
public class EmployeeAppConfig implements WebMvcConfigurer {
#Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setViewClass(JstlView.class);
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
#Bean
public SpringResourceTemplateResolver templateResolver() {
// SpringResourceTemplateResolver automatically integrates with Spring's own
// resource resolution infrastructure, which is highly recommended.
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(this.applicationContext);
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
// HTML is the default value, added here for the sake of clarity.
templateResolver.setTemplateMode(TemplateMode.HTML);
// Template cache is true by default. Set to false if you want
// templates to be automatically updated when modified.
templateResolver.setCacheable(true);
return templateResolver;
}
public void addResourceHandlers(ResourceHandlerRegistry resourceHandlerRegistry) {
resourceHandlerRegistry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
}
Try to define in webapp folder a hii.html file. helloGfg is returning hii but the resource with such name is missing.
Now that you have both the ViewResolver in place, you can add/set Order to them. Try,
templateResolver.setOrder(0); //or lower value
first I have to add
package com.crudoperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Description;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring3.SpringTemplateEngine;
import org.thymeleaf.spring3.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring3.view.ThymeleafViewResolver;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.crudoperation")
#Qualifier(value = "EmployeeAppConfig")
public class EmployeeAppConfig implements WebMvcConfigurer {
#Autowired
ApplicationContext applicationContext;
#Override
public void addResourceHandlers(ResourceHandlerRegistry resourceHandlerRegistry) {
resourceHandlerRegistry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Bean
public ClassLoaderTemplateResolver yourTemplateResolver() {
ClassLoaderTemplateResolver configurer = new ClassLoaderTemplateResolver();
configurer.setPrefix("/WEB-INF/views/");
configurer.setSuffix(".html");
configurer.setCharacterEncoding("UTF-8");
configurer.setOrder(0); // this is important. This way spring //boot will listen to both places 0 and 1
configurer.setCacheable(false);
return configurer;
}
#Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver srtr = new SpringResourceTemplateResolver();
srtr.setApplicationContext(applicationContext);
srtr.setPrefix("/WEB-INF/views/");
srtr.setSuffix(".html");
return srtr;
}
#Bean
#Description("Thymeleaf template engine with Spring integration")
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
return templateEngine;
}
#Bean
#Description("Thymeleaf view resolver")
public ViewResolver viewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setCharacterEncoding("UTF-8");
return viewResolver;
}
}
so that path can be found
I am working on a Spring Batch unit testing using the #SpringBatchTest annotation which is supposed to automatically add the beans for JobLauncherTestUtils and JobRepositoryTestUtils.
Here's the Job configuration class:
#Configuration
#EnableBatchProcessing
public class JobConfiguration {
#Bean
public Job getJob(JobBuilderFactory jobBuilderFactory,
#Qualifier("flow_master") Flow flowMaster) {
return jobBuilderFactory.get("job")
.incrementer(new RunIdIncrementer())
.start(flowMaster)
.build().build();
}
}
Here's the Test Class:
#ExtendWith(SpringExtension.class)
#SpringBatchTest
#ContextConfiguration(classes = JobConfiguration.class)
public class SpringBatchTest {
#Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
#Before
public void clearJobExecutions() {
this.jobRepositoryTestUtils.removeJobExecutions();
}
#Test
public void testMyJob() throws Exception {
JobParameters jobParameters = this.jobLauncherTestUtils.getUniqueJobParameters();
JobExecution jobExecution = this.jobLauncherTestUtils.launchJob(jobParameters);
Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
}
}
Problem:
I am getting the error messages:
Could not autowire. No beans of 'JobLauncherTestUtils' type found.
I have cloned some repo examples which are supposed to work but I am getting the same error for all of them.
Am I missing something?
You did not share your imports but you are probably mixing imports between junit4 and junit5. I'm not able to reproduce your error. Here is a complete example:
The job configuration class:
package com.example.demo;
import javax.sql.DataSource;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
#Configuration
#EnableBatchProcessing
public class MyJobConfig {
#Bean
public Job job(JobBuilderFactory jobs, StepBuilderFactory steps) {
return jobs.get("job")
.start(steps.get("step")
.tasklet((contribution, chunkContext) -> {
System.out.println("Hello world!");
return RepeatStatus.FINISHED;
}).build())
.build();
}
#Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("/org/springframework/batch/core/schema-h2.sql")
.build();
}
public static void main(String[] args) throws Exception {
ApplicationContext context = new AnnotationConfigApplicationContext(MyJobConfig.class);
JobLauncher jobLauncher = context.getBean(JobLauncher.class);
Job job = context.getBean(Job.class);
jobLauncher.run(job, new JobParameters());
}
}
The test class:
package com.example.demo;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.batch.test.JobRepositoryTestUtils;
import org.springframework.batch.test.context.SpringBatchTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
#ExtendWith(SpringExtension.class)
#SpringBatchTest
#ContextConfiguration(classes = MyJobConfig.class)
class MyJobConfigTest {
#Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
#Autowired
private JobRepositoryTestUtils jobRepositoryTestUtils;
#BeforeEach
public void clearJobExecutions() {
this.jobRepositoryTestUtils.removeJobExecutions();
}
#Test
public void testMyJob() throws Exception {
// given
JobParameters jobParameters = this.jobLauncherTestUtils.getUniqueJobParameters();
// when
JobExecution jobExecution = this.jobLauncherTestUtils.launchJob(jobParameters);
// then
Assertions.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
}
}
and the pom.xml file:
<?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>
<groupId>com.example</groupId>
<artifactId>so67767525</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>so67767525</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
<!-- While this has "boot" in the name, it does not bring any Spring Boot feature. -->
<!-- It is used to manage Spring projects dependencies that are known to work correctly together -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.4.6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
The test runs successfully without the error you mentioned.
When I run the application, it displays this error (error 401).
How fix this problem and thank's :
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing
this as a fallback. There was an unexpected error (type=Unauthorized,
status=401). Unauthorized
pom.xml :
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>app-back</artifactId>
<name>app-back</name>
<description>module app backend </description>
<packaging>war</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>
<properties>
<start-class>app.AppApplication</start-class>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<hibernate.core.version>5.4.2.Final</hibernate.core.version>
<maven.war.plugin.version>3.2.0</maven.war.plugin.version>
<jjwt.version>0.9.1</jjwt.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.core.version}</version>
</dependency>
<!-- Spring data JPA, default tomcat pool, exclude it -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt.version}</version>
</dependency>
</dependencies>
<build>
<finalName>app</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven.war.plugin.version}</version>
<configuration>
<packagingExcludes>WEB-INF/lib/tomcat-*.jar</packagingExcludes>
<warName>app</warName>
</configuration>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>validate</phase>
<goals><goal>copy-resources</goal></goals>
<configuration>
<outputDirectory>${basedir}/target/classes/static/</outputDirectory >
<resources>
<resource>
<directory>../app-front/dist/app-front</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
WebSecurityConfig.java :
package app.auth;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private static final String[] ACCEPTED_FILES = {"/*.html", "/*.css", "/*.js", "/*.jpg", "/*.png", "/*.ico", "/*.txt", "/*.svg", "/*.eot", "/*.woff2", "/*.ttf", "/*.woff"};
#Autowired
public UserDetailsService userDetailsService;
#Autowired
JwtTokenProvider jwtTokenProvider;
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
};
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Bean("authenticationManager")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public AuthenticationEntryPoint unauthorizedEntryPoint() {
return (request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/assets/**","/home/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()
.csrf().disable().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().authorizeRequests().antMatchers("/auth/sign-in").permitAll()
.and().authorizeRequests().antMatchers(ACCEPTED_FILES).permitAll()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/auth/admin/**").hasRole("ADMIN")
.antMatchers("/object/admin/**").hasRole("ADMIN")
.and().authorizeRequests().anyRequest().authenticated()
.and().exceptionHandling().authenticationEntryPoint(unauthorizedEntryPoint())
.and().apply(new JwtConfigurer(jwtTokenProvider))
.and().httpBasic().disable();
}
}
Appl.java :
package myApp.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#Configuration
#ComponentScan("app")
#EnableJpaRepositories("app.repositories")
#EntityScan( basePackages = {"app.entities"} )
#SpringBootApplication
#EnableAutoConfiguration
public class RefMetierApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(RefMetierApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(RefMetierApplication.class);
}
}
and this method in userServiceImpl.java :
#Override
public Map<String, String> login(appUser requestUser) {
UsernamePasswordAuthenticationToken authenticationTokenRequest = new UsernamePasswordAuthenticationToken(
requestUser.getUsername(), requestUser.getPassword());
try {
Authentication authentication = this.authenticationManager.authenticate(authenticationTokenRequest);
SecurityContext securityContext = SecurityContextHolder.getContext();
securityContext.setAuthentication(authentication);
appUser user = (appUser) authentication.getPrincipal();
String token = jwtTokenProvider.createToken(requestUser.getUsername(), user.getAuthorities());
Map<String, String> model = new HashMap<>();
model.put("username", requestUser.getUsername());
model.put("token", token);
if(user.hasRule(ParamsEnum.ROLE_ADMIN.getValue())) {
model.put("rule", "ADMIN");
}
else {
model.put("rule", "USER");
}
return model;
} catch (Exception e) {
e.printStackTrace();
throw new BadCredentialsException(ParamsEnum.BAD_CREDENTIALS.getValue());
}
}
You must not have setup ADMIN ROLE, for the User attempting request.
Hello i am trying to implement swagger with Spring REST, i am not using Spring Boot to create REST API's, i have used normal Spring REST API.
The problem when i run the application and if i navigate to this url
http://localhost:8080/spring-mvc-restfull-crud-example/swagger-ui.html
i am getting only the header of swagger-ui, there is nothing else. I am using Java config instead of XML config.
pom.xml
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.boraji.tutorial.spring</groupId>
<artifactId>spring-mvc-restfull-crud-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<dependencies>
<!-- Spring MVC Dependency -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.10.RELEASE</version>
</dependency>
<!-- Spring ORM -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.3.10.RELEASE</version>
</dependency>
<!-- Hibernate ORM -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.11.Final</version>
</dependency>
<!-- Hibernate-C3P0 Integration -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>5.2.11.Final</version>
</dependency>
<!-- c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!-- Mysql Connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.5</version>
</dependency>
<!-- Jackson API for JSON -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.7</version>
</dependency>
<!-- Servlet Dependency -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- this is for integrating swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-data-rest</artifactId>
<version>2.6.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<!-- Embedded Apache Tomcat required for testing web application -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
WebConfig.java
package com.boraji.tutorial.spring.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.google.common.base.Predicates;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.boraji.tutorial.spring.controller" })
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
BookController.java
package com.boraji.tutorial.spring.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.boraji.tutorial.spring.model.Book;
import com.boraji.tutorial.spring.service.BookService;
import io.swagger.annotations.Api;
#CrossOrigin(origins = "*")
#RestController
public class BookController {
#Autowired
private BookService bookService;
/*---Add new book---*/
#PostMapping("/book")
public ResponseEntity<?> save(#RequestBody Book book) {
long id = bookService.save(book);
return ResponseEntity.ok().body("New Book has been saved with ID:" + id);
}
/*---Get a book by id---*/
#GetMapping("/book/{id}")
public ResponseEntity<Book> get(#PathVariable("id") long id) {
Book book = bookService.get(id);
return ResponseEntity.ok().body(book);
}
/*---get all books---*/
#GetMapping("/book")
public ResponseEntity<List<Book>> list() {
List<Book> books = bookService.list();
return ResponseEntity.ok().body(books);
}
/*---Update a book by id---*/
#PutMapping("/book/{id}")
public ResponseEntity<?> update(#PathVariable("id") long id, #RequestBody Book book) {
bookService.update(id, book);
return ResponseEntity.ok().body("Book has been updated successfully.");
}
/*---Delete a book by id---*/
#DeleteMapping("/book/{id}")
public ResponseEntity<?> delete(#PathVariable("id") long id) {
bookService.delete(id);
return ResponseEntity.ok().body("Book has been deleted successfully.");
}
}
In the resources folder, i have db.properties file
# MySQL properties
mysql.driver=com.mysql.cj.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/bookdb
mysql.user=root
mysql.password=root
# Hibernate properties
hibernate.show_sql=true
hibernate.hbm2ddl.auto=update
#C3P0 properties
hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=20
hibernate.c3p0.acquire_increment=1
hibernate.c3p0.timeout=1800
hibernate.c3p0.max_statements=150
MyWebAppInitializer.java
package com.boraji.tutorial.spring.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { AppConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
can you please anyone help me that what is wrong in this? is there anything that i need to add?
You have not defined Docket bean and neither you have used the #EnableSwagger2
The configuration of Swagger mainly centers around the Docket bean. Swagger 2 is enabled through the #EnableSwagger2 annotation. Refer the below code.
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket customImplementation() {
return new Docket(DocumentationType.SWAGGER_2).pathMapping("/data").apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
return new ApiInfo("ISW ADR Application",
"ADR or is another business line within the Issuer services business group."
+ "The primary functionalities of ADR are maintained within the DR system (mainframe) "
+ "Four main functionalities that are imported : "
+" 1) Dividend Announcements"
+ " 2) Depositary Service fees"
+ " 3) DR Fees"
+ " 4) DR Gross revenue.",
"ADR V2", "Terms of service", "xyz", "License of API", "API license URL");
}
}
You have not enabled swagger using #EnableSwagger2 and also have not returned a Docket Bean. Refer this.
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket demoApi() {
return new Docket(DocumentationType.SWAGGER_2).select()
.apis(RequestHandlerSelectors.basePackage("com.example.demo"))
.paths(PathSelectors.regex("/person.*")).build();
}
}