HikariCP for MongoDB in springboot - mongodb

I am looking to create a connection pool - for mongoDB in Springboot. I am currently making use of Springdata Mongo repositories to connect to DB and collections but unsure of how to create the datapool connection
Here is the current implementation
PersonRepository.java
package com.test.TestAPI.repository;
import java.util.List;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import com.test.TestAPI.dto.Person;
#Repository
public interface PersonRepository extends MongoRepository<Person, String> {
}
PersonService
package com.test.TestAPI.service.impl;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.test.TestAPI.repository.PersonRepository;
import com.test.TestAPI.dto.Person;
#Service
public class PersonService {
#Autowired
private PersonRepository personRepo;
public List<Person> findAllPersons() {
return personRepo.findAll();
}
public Person createPerson(Person person) {
return personRepo.save(person);
}
}
PersonController
package com.test.TestAPI.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.test.TestAPI.service.impl.PersonService;
import com.test.TestAPI.dto.Person;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
#RestController
#RequestMapping(path="/v1/personController")
#Api(value="Controller for Person document")
public class PersonController {
#Autowired
PersonService service;
#GetMapping("/getAllPersons")
#ApiOperation(produces = MediaType.APPLICATION_JSON_VALUE, httpMethod = "GET", response = List.class,
value = "getAllPersons from the database", notes = "Sample note")
public ResponseEntity<List<Person>> getAllPersons(){
List<Person> personList = service.findAllPersons();
return new ResponseEntity<List<Person>>(personList, HttpStatus.OK);
}
}
SimpleCommandLineConfig
package com.test.TestAPI.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.stereotype.Component;
import com.test.TestAPI.repository.PersonRepository;
import com.test.TestAPI.dto.Person;
#Component
#Order(3)
public class SimpleCommandLineConfig implements CommandLineRunner {
#Autowired
PersonRepository repo;
#Override
public void run(String... args) throws Exception {
// TODO Auto-generated method stub
System.out.println("third command line runner");
System.out.println(repo.save(new Person("rr","rr",4)));
}
}
App.java
package com.test.TestAPI.main;
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
/**
* Hello world!
*
*/
#SpringBootApplication
#ComponentScan(basePackages= {"com.test.TestAPI"})
#EnableMongoRepositories(basePackages= {"com.test.TestAPI.repository"})
public class App
{
public static void main(String[] args) throws Exception {
SpringApplication.run(App.class, args);
}
}
Also, I would like to know if spring data repos like a custom repo for MongoDB takes care of connection pool mechanism? How does connection pooling happen in that case? Could you please help me on this

I think I found an answer for this. Just like we use JDBC templates for RDBMS to store the databases, spring provides something called MongoTemplates which forms a connection pool based on the db configuration given
Here is a sample implementation
MongoClientFactory.java
public #Bean MongoClientFactoryBean mongo() throws Exception {
MongoClientFactoryBean mongo = new MongoClientFactoryBean();
mongo.setHost("localhost");
MongoClientOptions clientOptions = MongoClientOptions.builder().applicationName("FeddBackAPI_DB")
.connectionsPerHost(2000)
.connectTimeout(4000)
//.maxConnectionIdleTime(1000000000)
.maxWaitTime(3000)
.retryWrites(true)
.socketTimeout(4000)
.sslInvalidHostNameAllowed(true)//this is very risky
.build();
mongo.setMongoClientOptions(clientOptions);
return mongo;
}
DataSourceConfig.java (Another config class. Same config class can also be used to define all beans)
package com.fmr.FeedBackAPI.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.Environment;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import com.mongodb.Mongo;
import com.mongodb.MongoClient;
#Configuration
#Import(value=MongoClientFactory.class)
public class DataSourceConfig {
#Autowired
Mongo mongo;
#Autowired
Environment env;
#Bean
public String test() {
System.out.println("mongo"+mongo);
return "rer";
}
private MongoTemplate mongoTemplate() {
MongoDbFactory factory = new SimpleMongoDbFactory((MongoClient) mongo, "mongo_test");
MongoTemplate template = new MongoTemplate(factory);
return template;
}
#Bean
#Qualifier(value="customMongoOps")
public MongoOperations mongoOps() {
MongoOperations ops = mongoTemplate();
return ops;
}
#Bean
public MongoDbFactory factory() {
MongoDbFactory factory = new SimpleMongoDbFactory((MongoClient) mongo, "mongo_test");
return factory;
}
// #Bean
// public GridFsTemplate gridFsTemplate() {
// return new GridFsTemplate(mongo, converter)
// }
#Bean
public javax.sql.DataSource dataSource() {
HikariDataSource ds = new HikariDataSource();
ds.setMaximumPoolSize(100);
// ds.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
// ds.setJdbcUrl(env.getProperty("spring.datasource.url"));;
//ds.setUsername(env.getProperty("spring.datasource.username"));
//ds.setPassword(env.getProperty("spring.datasource.password"));
ds.addDataSourceProperty("cachePrepStmts", true);
ds.addDataSourceProperty("prepStmtCacheSize", 250);
ds.addDataSourceProperty("prepStmtCacheSqlLimit", 2048);
ds.addDataSourceProperty("useServerPrepStmts", true);
return ds;
}
}
Now autowire the template/mongoOperations in you dao implementation or service and use it
package com.fmr.FeedBackAPI.service.impl;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import com.fmr.FeedBackAPI.dto.ConfigDTO;
import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Query.query;
#Service
public class PlanConfigService {
#Autowired
#Qualifier(value="customMongoOps")
MongoOperations mongoOps;
public List<ConfigDTO> createConfigDTOList(List<ConfigDTO> configDTOList) {
List<ConfigDTO> configList = new ArrayList<>();
if(!mongoOps.collectionExists(ConfigDTO.class)) {
mongoOps.createCollection("ConfigDTO_table");
}
//create the configDTOList
mongoOps.insert(configDTOList, ConfigDTO.class);
configList = mongoOps.findAll(ConfigDTO.class, "ConfigDTO_table");
return configList;
}
public List<ConfigDTO> createConfigDTO(ConfigDTO configDTO) {
List<ConfigDTO> configList = new ArrayList<>();
if(!mongoOps.collectionExists(ConfigDTO.class)) {
mongoOps.createCollection("ConfigDTO_table");
}
//create the configDTOList
mongoOps.save(configDTO);
configList = mongoOps.find(query(where("planId").is(configDTO.getPlanId())), ConfigDTO.class,"ConfigDTO_table");
return configList;
}
}
Here is the application.properties (this is the default instance running in local)
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=mongo_test
spring.data.mongodb.repositories=true
#
spring.datasource.url=jdbc:mongodb://localhost:27017/mongo_test

Related

Spring boot - Null pointer exception while mocking MongoTemplate.getCollection()

I have written a service class which uses MongoTemplate.getCollection().
But while writing the test case I am mockingMongoTempalte and MongoCollection but getting NullPointerException.
Following is the code.
Service class
import com.mongodb.client.MongoCollection;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.NoSuchElementException;
#Service
public class ABCService {
#Autowired
MongoTemplate mongoTemplate;
public byte[] exportFrom(String collectionName) {
if(!mongoTemplate.collectionExists(collectionName))
throw new NoSuchElementException("Collection does not exist");
MongoCollection<Document> collection = mongoTemplate.getCollection(collectionName);
do something
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Test Class:
import com.mongodb.BasicDBObject;
import com.mongodb.client.MongoCollection;
import org.bson.Document;
import org.json.JSONObject;
import org.junit.Before;
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.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.mongodb.core.MongoTemplate;
import static org.mockito.Mockito.*;
#ExtendWith(MockitoExtension.class)
class ABCServiceTest {
#Mock
private MongoTemplate mongoTemplate;
#Mock
private MongoCollection<Document> documentMongoDBCollection;
#InjectMocks
private ABCService abcService ;
#Test
void exportFrom() throws Exception {
JSONObject obj = new JSONObject();
obj.put("_id", "1234");
obj.put("accessField", "xyz 123");
Document doc = Document.parse(obj.toString());
byte[] pos = obj.toString().getBytes();
when(mongoTemplate.collectionExists("DataCollection"))
.thenReturn(true);
when(mongoTemplate.getCollection(any(String.class)))
.thenReturn(documentMongoDBCollection); // **This returning Null pointer exception**
when(abcService .exportFrom("DataCollection"))
.thenReturn(pos);
byte[] result = abcService .exportFrom("DataCollection");
Assertions.assertNotNull(result);
verify(mongoTemplate,times(1)).collectionExists("DataCollection");
verify(mongoTemplate,times(1)).getCollection("DataCollection");
}
}
Expecting to throw object to complete the mocking of Mongo template.

Field authorMongoRepository required a bean of type that could not be found

Description:
Field authorMongoRepository in com.example.SpringReturnObject.Mongo.Controller.AuthorController required a bean of type 'com.example.SpringReturnObject.Rest.Controller.AuthorMongoRepository' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.example.SpringReturnObject.Rest.Controller.AuthorMongoRepository' in your configuration.
AuthorMongoRepository class
package com.example.SpringReturnObject.Rest.Controller;
import com.example.SpringReturnObject.Mongo.Model.Author;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public interface AuthorMongoRepository extends MongoRepository<Author, String> {
List<Author> findByUsernameContainingIgnoreCase(String username);
List<Author> findByArticles_titleContainingIgnoreCase(String title);
}
AddnewDocument.java
package com.example.SpringReturnObject.Mongo.Implementation;
import com.example.SpringReturnObject.Mongo.Model.Article;
import com.example.SpringReturnObject.Mongo.Model.Author;
import com.example.SpringReturnObject.Rest.Controller.AuthorMongoRepository;
import com.example.SpringReturnObject.Rest.Controller.MongoController;
import org.springframework.beans.factory.annotation.Autowired;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class AddNewDoc implements MongoController {
#Autowired
AuthorMongoRepository authorMongoRepository;
#Override
public List<Author> getAllList() {
SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy");
authorMongoRepository.deleteAll();
final Article article1;
try {
article1 = new Article("Spring Boot - MongoDB + Data + Web"
, "MongoDB", df.parse("10/5/2018"));
final Article article2 = new Article("Spring Boot - MongoDB + Data + Web"
, "H2 Console", df.parse("2/3/2016"));
final Article article3 = new Article("Spring Cloud - Zuul + Eureka + Rest Web", "Load Balancer with Zuul", df.parse("5/1/2018"));
final Article article4 = new Article("Spring Cloud - Feign"
, "Feign Client + Eureka + Rest", df.parse("5/6/2018"));
Author author1 = new Author("Melardev", Arrays.asList(article1, article2));
Author author2 = new Author("Momo", Arrays.asList(article3, article4));
authorMongoRepository.save(author1);
authorMongoRepository.save(author2);
}
catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
MongoControllerInterface
package com.example.SpringReturnObject.Rest.Controller;
import com.example.SpringReturnObject.Mongo.Model.Author;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#RestController
public interface MongoController {
#GetMapping("/author")
List<Author> getAllList();
}
ApplicationStartup.java
package com.example.SpringReturnObject;
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.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
#EnableMongoRepositories(basePackages = "com.example.SpringReturnObject.Rest.Controller.AuthorMongoRepository")
#EnableAutoConfiguration
#Configuration
#ComponentScan({"com.example.*"})
#EntityScan({"com.example.*"})
#SpringBootApplication
public class SpringReturnObjectApplication {
public static void main(String[] args) {
SpringApplication.run(SpringReturnObjectApplication.class, args);
}
}

how avoid to access to other data users. Spring boot + MongoDB

I'm developing a web application with Spring Boot and MongoDB. I'm following the MVC model.
I have a view which shows a list of stored data, but the app ignores the logged user and shows every objects.
https://i.stack.imgur.com/zl7TC.png
Here, the first row was added by another user, but it's showed anyway.
How could I get only the object allowed to the authenticated user?.
The only way I can see is checking the user Id after each query and get only the object of the given user. I think that there should be a better way to do this.
The code is the following:
Entity
import java.io.Serializable;
import java.util.Collection;
import java.util.Set;
import org.springframework.data.mongodb.core.index.IndexDirection;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document;
#Document(collection = "trackings")
public class Tracking extends Entity implements Serializable {
private static final long serialVersionUID = -1249902722123443448L;
#Indexed(unique = true, direction = IndexDirection.DESCENDING)
private String trackingName;
private String SoftwareName;
#DBRef
private Set<Alarm> alarms;
public String getTrackingName() {
return trackingName;
}
public void setTrackingName(String trackingName) {
this.trackingName = trackingName;
}
public String getSoftwareName() {
return SoftwareName;
}
public void setSoftwareName(String softwareName) {
SoftwareName = softwareName;
}
public Collection<Alarm> getAlarms() {
return alarms;
}
public void setAlarms(Set<Alarm> alarms) {
this.alarms = alarms;
}
}
Repository
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import us.etsii.fvt.domains.Tracking;
#Repository
public interface TrackingRepository extends MongoRepository<Tracking, String>{
Tracking findByTrackingName(String name);
}
Controller
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import us.etsii.fvt.domains.Alarm;
import us.etsii.fvt.domains.Tracking;
import us.etsii.fvt.domains.User;
import us.etsii.fvt.services.TrackingService;
import us.etsii.fvt.services.UserService;
#Controller
public class TrackingController {
#Autowired
private UserService userService;
#Autowired
private TrackingService trackingService;
#RequestMapping(value = { "/tracking" }, method = RequestMethod.GET)
public ModelAndView tracking() {
ModelAndView modelAndView = new ModelAndView();
// AƱadimos el usuario al modelo
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
User user = userService.findUserByEmail(auth.getName());
modelAndView.addObject("currentUser", user);
modelAndView.addObject("fullName", user.getFullname());
// AƱadimos la lista de trackings al modelo
List<Tracking> trackings = trackingService.findAll();
modelAndView.addObject("trackings", trackings);
// Devolvemos el modelo
modelAndView.setViewName("tracking");
return modelAndView;
}
...
}
Service
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import us.etsii.fvt.domains.Tracking;
import us.etsii.fvt.repositories.TrackingRepository;
#Service
public class TrackingService {
#Autowired
private TrackingRepository trackingRepository;
public Tracking findTrackingByName(String name) {
return trackingRepository.findByTrackingName(name);
}
public void saveTracking(Tracking tracking) {
trackingRepository.save(tracking);
}
public List<Tracking> findAll() {
return trackingRepository.findAll();
}
public Tracking findById(String id) {
Optional<Tracking> t = trackingRepository.findById(id);
if(!t.isPresent()) {
return null;
}
return t.get();
}
public void remove(String id) {
trackingRepository.deleteById(id);
}
}
There are ambiguous points in your question but assuming you have an User Entity:
You should get the logged in user from Spring Security
You should include a relation of User Entity to Tracking Entity (include User ID information in Tracking records)
Then you should query the mongo db Tracking Entity with the given user id.
You can use standard query by field functionality of Spring Repository.

Reading Multiple excel File Using Spring Batch Extension

I am trying to read multiple excel files using Spring-Bath-Excel. In my scenario i don't know i advance how many files client will process i.e. if data would be very large, excel file will be split into multiple files like records1.xls ,records2.xls, records3.xls..
Is there any kind of MultiResourceItemReader available in Spring-Batch-Excel? I tried to set multiple resources at run time and also tried to use the patterns records*.xls but PoiItemReader did't allow me to do that .
I am using PoiItemReader for that .
To Read Multiple Excel
package com.abc.ingestion.job.dci;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
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.support.RunIdIncrementer;
import org.springframework.batch.extensions.excel.RowMapper;
import org.springframework.batch.extensions.excel.streaming.StreamingXlsxItemReader;
import org.springframework.batch.extensions.excel.support.rowset.DefaultRowSetFactory;
import org.springframework.batch.extensions.excel.support.rowset.StaticColumnNameExtractor;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.file.MultiResourceItemReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
#Configuration
#EnableBatchProcessing
public class BatchConfig {
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Autowired
private StepBuilderFactory stepBuilderFactory;
// Create input folder in resources
#Value("input/DCI*.xlsx")
private Resource[] inputResources;
#Bean
public MultiResourceItemReader<CouncilMapper> multiResourceItemReader() {
MultiResourceItemReader<CouncilMapper> resourceItemReader = new MultiResourceItemReader<>();
resourceItemReader.setResources(inputResources);
resourceItemReader.setDelegate(reader());
return resourceItemReader;
}
private RowMapper<CouncilMapper> excelRowMapper() {
return new Mapper();
}
#SuppressWarnings({ "rawtypes", "unchecked" })
#Bean
public StreamingXlsxItemReader<CouncilMapper> reader() {
final String[] COLUMNS = {"Reg_Type","RegUnder","registration_no","registration_date","course","Other_Course","LRegDate","council_name","full_name","CatName","Other_Category","father_name","mother_name","gender","nationality","date_of_birth","place_of_birth","permanent_address","business_address","current_city","current_state","permanent_city","mobile_number","OfficialTelephone","email","aadhar_number","PanNo","IsDeleted","CreatedDate","UpdatedDate","speciality_name"};
var factory = new DefaultRowSetFactory();
factory.setColumnNameExtractor(new StaticColumnNameExtractor(COLUMNS));
StreamingXlsxItemReader<CouncilMapper> reader = new StreamingXlsxItemReader<>();
reader.setLinesToSkip(1);
reader.setRowSetFactory(factory);
reader.setRowMapper(excelRowMapper());
return reader;
}
#Bean
ItemWriter<CouncilMapper> writer() {
return new Writer();
}
#Bean
public Job readFilesJob() {
return jobBuilderFactory
.get("readFilesJob")
.incrementer(new RunIdIncrementer())
.start(excelFileStep())
.build();
}
#Bean
public Step excelFileStep() {
return stepBuilderFactory.get("excelFileStep")
.<CouncilMapper, CouncilMapper>chunk(5)
.reader(multiResourceItemReader())
.writer(writer())
.build();
}
}
Mapper Class
package com.abc.ingestion.job.dci;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.IntStream;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.batch.extensions.excel.RowMapper;
import org.springframework.batch.extensions.excel.support.rowset.RowSet;
public class Mapper implements RowMapper<CouncilMapper> {
#Override
public CouncilMapper mapRow(RowSet rowSet) throws Exception {
var rowSetMetaData = rowSet.getMetaData();
String[] columnNames = rowSetMetaData.getColumnNames();
String[] rowData = rowSet.getCurrentRow();
var mapper = new ObjectMapper();
Map<String, String> excelData = new HashMap<>();
IntStream.range(0, columnNames.length).forEach(index -> excelData.put(columnNames[index], rowData[index]));
return mapper.convertValue(excelData, CouncilMapper.class);
}
}

Spring-boot, unable to autowire a class.No default constructor found Exception is raised

I am new to spring-boot. After i moved a class to different package (other the one contains 'Application'), Could not instantiate bean class: No default constructor found Exception is raised.
Before (workable code)
package com.server;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Controller;
#Configuration
#ComponentScan(basePackages = {"com.server" })
#EnableAutoConfiguration
#Profile({ "default" })
#Controller
public class Application {
private static Log logger = LogFactory.getLog(Application.class);
public static void main(String[] args) {
logger.info("Starting Application...");
SpringApplication.run(Application.class, args);
}
}
A piece of code from http://bitwiseor.com/2013/09/20/creating-test-services-with-spring-boot/
package com.server;
import java.util.Collections;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
#Configuration
#Controller
#Profile({ "default" })
class Franchise {
private JdbcTemplate jdbcTemplate;
#Autowired
public Franchise(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
#ResponseBody
#RequestMapping("/api/franchise/{id}")
String franchiseId(#PathVariable Long id) {
try {
return jdbcTemplate.queryForMap("SELECT id, title FROM franchises WHERE id=?", id).toString();
} catch(EmptyResultDataAccessException ex) {
return Collections.EMPTY_MAP.toString();
}
}
#ResponseBody
#RequestMapping("/api/franchise")
String franchises() {
try {
return jdbcTemplate.queryForList("SELECT id, title FROM franchises").toString();
} catch(EmptyResultDataAccessException ex) {
return Collections.EMPTY_MAP.toString();
}
}
}
I am able to bring up the server when class 'Application' and 'Franchise' are located in the same package. However, when I moved the class 'Franchise' into another package as shown below, I've got this exception: Could not instantiate bean class: No default constructor found Exception is raised.
package com.server.api;
import java.util.Collections;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
#Configuration
#Controller
#Profile({ "default" })
class Franchise {
private JdbcTemplate jdbcTemplate;
#Autowired
public Franchise(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
#ResponseBody
#RequestMapping("/api/franchise/{id}")
String franchiseId(#PathVariable Long id) {
try {
return jdbcTemplate.queryForMap("SELECT id, title FROM franchises WHERE id=?", id).toString();
} catch(EmptyResultDataAccessException ex) {
return Collections.EMPTY_MAP.toString();
}
}
#ResponseBody
#RequestMapping("/api/franchise")
String franchises() {
try {
return jdbcTemplate.queryForList("SELECT id, title FROM franchises").toString();
} catch(EmptyResultDataAccessException ex) {
return Collections.EMPTY_MAP.toString();
}
}
}
How can I solve this problem if I wanted to move this class into a different package?
Thanks!
Edit: I found a solution
When I removed the following tag, I am able to put the class into separate package.
#Configuration
#Profile({ "default" })
But I have no idea why...
It looks to me like your Franchise class is package private (the default visibility for a java class). That would explain everything (and no need to involve Spring or anything other than a compiler). To fix it just declare your class to be "public".
Marten is also correct that #Configuration is probably not want you mean for the Franchise (but in this case it's harmless).