I use javaee 8 for my project and have this classes :
public class PersonRepository {
#Inject
#Mongo(collection = "users")
private MongoCollection collection;
// define some methods ....
}
#ApplicationScoped
public class MongoProducer {
#Inject
private MongoClient mongoClient;
#Produces
#Mongo
protected MongoCollection produceCollection(InjectionPoint ip) {
Mongo mongo = getMongoAnnotation(ip);
return mongoClient.getDatabase("sample").getCollection(mongo.collection());
}
private Mongo getMongoAnnotation(InjectionPoint ip) {
return ip.getAnnotated().getAnnotation(Mongo.class);
}
}
#MongoClientDefinition(
name = "mongoClient",
dbName = "sample",
username = "admin",
password = "adminpass"
)
public class MongoConnectionConfig {
}
Unfortunately mongoClient has not any method for get database name currently connected to that. (maybe i cant find that !)
How can scan MongoClientDefinition annotation from produceCollection method ?
I want set database name from that annotation . (replace "sample") .
Note : I created CDI extension for MongoClientDefinition .
simple idea is BeanManager :
I modified my extension and add getter method for dbName .
full project on github
#ApplicationScoped
public class MongoProducer {
#Inject
private MongoClient mongoClient;
#Inject
private BeanManager bm;
#Produces
#Mongo
protected MongoCollection produceCollection(InjectionPoint ip) {
String dbName = bm.getExtension(MongoClientExtension.class).getDatabaseName();
Mongo mongo = getMongoAnnotation(ip);
return mongoClient.getDatabase(dbName).getCollection(collectionName,mongo.collection());
}
private Mongo getMongoAnnotation(InjectionPoint ip) {
return ip.getAnnotated().getAnnotation(Mongo.class);
}
}
Related
I'm configuring mongoDB in my spring boot application like this:
#Configuration
#SpringBootApplication
public class ConfigDbApp extends SpringBootServletInitializer {
#Value("${myapp.mongodb.uri}")
private String mongoDbUri;
[...]
#Bean
public MongoClient mongoClient() {
MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(mongoDbUri.trim()))
.build();
return MongoClients.create(mongoClientSettings);
}
[...]
}
The database uri is:
myapp.mongodb.uri=mongodb://localhost:27017/myApp?sslInvalidHostNameAllowed=true&streamType=netty&ssl=false
The connection is fine but instead of connecting to "myApp" database it connect to "test" database (the default).
If I use the spring property:
spring.data.mongodb.uri=mongodb://localhost:27017/myApp?sslInvalidHostNameAllowed=true&streamType=netty&ssl=false
it works well, but I don't want to use it because I can have diferent apps in the same server reading the same configuration file.
Any suggestion is appreciated, thanks.
This worked with me : override the database name
#Configuration
public class MongoConfig extends AbstractMongoClientConfiguration {
#Value("${spring.data.mongodb.uri}")
private String uri;
#Value("${spring.data.mongodb.database}")
private String database;
#Override
protected String getDatabaseName() {
return database;
}
#Bean
#Override
public MongoClient mongoClient() {
final ConnectionString connectionString = new ConnectionString(uri);
final MongoClientSettings.Builder mongoClientSettings = MongoClientSettings.builder().applyConnectionString(connectionString)
.applyToConnectionPoolSettings(builder -> builder.applySettings(connectionPoolSettings()));
return MongoClients.create(mongoClientSettings.build());
}
private ConnectionPoolSettings connectionPoolSettings() {
return ConnectionPoolSettings.builder()
.maxSize(50)
.maxWaitTime(20, TimeUnit.SECONDS)
.maxConnectionIdleTime(20, TimeUnit.SECONDS)
.maxConnectionLifeTime(60, TimeUnit.SECONDS).build();
}
}
I am a student studying java. I want to make a simple membership registration using Spring boot mongoDB, but an error occurs and I ask a question.
my source code
MemberDTO
public class MemberDTO {
#Id
private String memberId;
private String memberPwd;
private String memberName;
private String memberEName;
private String memberCompany;
private String memberPhone;
private String memberZipCode;
private String memberAddress;
private String memberAddressDetail;
private String memberAuth;
#CreatedDate
private Date createdDate;
}
MemberController
#Controller
#RequestMapping("/member")
public class MemberController {
#Autowired
private MemberSv memberSv;
#RequestMapping(value = "/join", method = RequestMethod.POST)
public String membersave(MemberDTO memberDTO)
{
memberSv.membersave(memberDTO);
return "join_form";
}
}
MemberSv
#Repository
public interface MemberSv extends MongoRepository<MemberDTO, String> {
MemberDTO membersave(MemberDTO memberDTO);
}
MemberSvImp
#Service
#Transactional
public class MemberSvImp {
#Autowired
private MemberSv memberSv;
public MemberDTO membersave(MemberDTO memberDTO) {
return memberSv.save(memberDTO);
}
}
Spring boot main method
#EnableMongoRepositories(basePackageClasses =com.example.accountproject.models.interfaces.MemberSv.class)
#SpringBootApplication
public class AccountProjectApplication {
public static void main(String[] args) {
SpringApplication.run(AccountProjectApplication.class, args);
}
}
Error
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'memberController':
Unsatisfied dependency expressed through field 'memberSv'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'memberSv' defined in com.example.accountproject.models.interfaces.MemberSv defined in #EnableMongoRepositories declared on AccountProjectApplication: Invocation of init method failed;
nested exception is org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract com.example.accountproject.documents.MemberDTO com.example.accountproject.models.interfaces.MemberSv.membersave(com.example.accountproje ct.documents.MemberDTO)! Reason: No property membersave found for type MemberDTO! Did you mean 'memberName'?; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property membersave found for type MemberDTO! Did you mean 'memberName'?
The first thing is you cannot save the MemberDTO as it is through MongoRepository. You need to persist the entity object rather than a POJO.
You need to add a MongoDB configuration By annotating the configuration class with #EnableMongoRepositories
And finally, you need to make sure that you have created a collection (the MongoDB equivalent of a table in SQL) in MongoDB to persists the Member Document (the MongoDB equivalent of a record in a table in SQL)
MongoDB configuration class.
#Configuration
#EnableTransactionManagement
#EnableMongoRepositories(basePackages = {"com.example.accountproject.models"})
#PropertySource({"classpath:application.properties"})
public class MongoDBConfiguration{
#Value("${spring.data.mongodb.host}") // set host in application.properties file
private String mongoHost;
#Value("${spring.data.mongodb.port}") // set port in application.properties file
private int mongoPort;
#Value("${spring.data.mongodb.database}") // set DB name in application.properties file
private String mongoDatabase;
#Value("${spring.data.mongodb.user}") // set user in application.properties file
private String mongoUser;
#Value("${spring.data.mongodb.password}") // set password in application.properties file
private String mongoPassword;
#Bean
public MongoDbFactory mongoDbFactory() {
MongoCredential mongoCredential = MongoCredential.createCredential(mongoUser, mongoDatabase, mongoPassword.toCharArray());
ServerAddress serverAddress = new ServerAddress(mongoHost, mongoPort);
MongoClient mongoClient = new MongoClient(serverAddress, Arrays.asList(mongoCredential));
return new SimpleMongoDbFactory(mongoClient, mongoDatabase);
}
#Bean
public MongoTemplate mongoTemplate(#Autowired MongoDbFactory mongoDbFactory) {
MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory);
return mongoTemplate;
}
}
And remove the #EnableMongoRepositories Annotation in the AccountProjectApplication class
introduce a new Model class for the Entity Member(Let's say the collection name is 'register')
#Document(collection = 'register')
public class Member{
#Id
private String memberId;
private String memberPwd;
private String memberName;
private String memberEName;
private String memberCompany;
private String memberPhone;
private String memberZipCode;
private String memberAddress;
private String memberAddressDetail;
private String memberAuth;
#CreatedDate
private Date createdDate;
//getters and setters
}
MemberController
#Controller
#RequestMapping("/member")
public class MemberController {
#Autowired
private MemberSvImp memberService;
#RequestMapping(value = "/join", method = RequestMethod.POST)
public String membersave(MemberDTO memberDTO)
{
memberService.membersave(memberDTO);
return "join_form";
}
}
Service layer
#Service
#Transactional
public class MemberSvImp {
#Autowired
private MemberSv memberSv;
public Member membersave(MemberDTO memberDTO){
Member member = new Member();
//set member attributes through memberDTO
//ex : member.setMemberName=memeberDTO.getMemeberName();
return memberSv.save(member);
}
}
Repository Class's Base Entity should be changed to Member
#Repository
public interface MemberSv extends MongoRepository<Member, String> {
//you can call save(Entity) or saveAndFlush(Entity) of JPARespository directly without defining any custom methods to save new member.
}
SUGGESTION : Better if you can rename the repository and service class to show their purpose
MemberSv -> MemberRespository
MemberSvImp - > MemberService
where is your configuration file for setting up credentials??
I'm quite a newbie to Spring boot, but here's the problem I'm facing now:
// Application.java
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Autowired
private Cluster cluster = null;
#PostConstruct
private void migrateCassandra() {
Database database = new Database(this.cluster, "foo");
MigrationTask migration = new MigrationTask(database, new MigrationRepository());
migration.migrate();
}
}
So basically, I'm trying to bootstrap a spring application, and after that, do some cassandra migrations.
I also have defined a repository for my user model:
// UserRepo.java
public interface UserRepo extends CassandraRepository<User> {
}
Now I'm trying to test my repo class using the following simple test case:
// UserRepoTest.java
#RunWith(SpringRunner.class)
#AutoConfigureTestDatabase(replace = Replace.NONE)
#DataJpaTest
public class UserRepoTest {
#Autowired
private UserRepo userRepo = null;
#Autowired
private TestEntityManager entityManager = null;
#Test
public void findOne_whenUserExists_thenReturnUser() {
String id = UUID.randomUUID().toString();
User user = new User();
user.setId(id);
this.entityManager.persist(user);
assertEquals(this.userRepo.findOne(user.getId()).getId(), id);
}
#Test
public void findOne_whenUserNotExists_thenReturnNull() {
assertNull(this.userRepo.findOne(UUID.randomUUID().toString()));
}
}
I would expect the test to pass, but instead, I got an error saying "No qualifying bean of type 'com.datastax.driver.core.Cluster' available". It looks like spring failed to autowire the cluster object, but why is that? How do I fix this? Thanks a lot!
The test environment needs to know where your beans are defined, so you have to tell it the location.
In your test class, add the #ContextConfiguration annotation:
#RunWith(SpringRunner.class)
#AutoConfigureTestDatabase(replace = Replace.NONE)
#DataJpaTest
#ContextConfiguration(classes = {YourBeans.class, MoreOfYourBeans.class})
public class UserRepoTest {
#Autowired
private UserRepo userRepo = null;
#Autowired
private TestEntityManager entityManager = null;
I researched on ElasticSearch and knew how to connect it but I need to create a model using anotation #Document() like this.
#Document(indexName = "resource", type = "person", shards = 1, replicas = 0)
public class Person {
#Id
private String id;
private String firstName;
private String lastName;
}
I create a Repository accordingly:
public interface PersonRepository extends ElasticsearchRepository<Person ,Long> { }
My purpose is that I don't want create model anymore. I want to use Json file instead so my repository should be like this:
public interface PersonRepository extends ElasticsearchRepository<String,Long> { }
My problem is that I don't know the configuration of ElasticSearch in order to create indexName and type without using #Document(). I wonder if my idea is possible. I hope everyone can give me some hints. I really appreciate your supports. Thank you very much in advance.
This is my current configuration:
#Configuration
#PropertySource(value = "classpath:elasticsearch.properties")
#EnableElasticsearchRepositories(basePackages = "spring.demo")
public class ElasticsearchConfiguration {
#Resource
private Environment environment;
#Bean
public Client client() throws UnknownHostException {
String host = environment.getProperty("elasticsearch.host");
int port = Integer.parseInt(environment.getProperty("elasticsearch.port"));
String cluster = environment.getProperty("cluster.name");
Settings settings = Settings.settingsBuilder()
.put("cluster.name", cluster)
.build();
Client client = TransportClient.builder().settings(settings).build()
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(host), port));
return client;
}
#Bean
public ElasticsearchOperations elasticsearchTemplate() throws UnknownHostException {
return new ElasticsearchTemplate(client());
}
}
I'm writing unit test for an web app, and I've got problem with service layer. App is using Spring Data JPA, and H2 database for tests.
Here is my test class:
#WebAppConfiguration
#ContextConfiguration(classes = {TestConfiguration.class})
#TestPropertySource(locations = "classpath:test.properties")
#Transactional
public class AuthorCreateServiceTest extends AbstractTestNGSpringContextTests {
#Mock
private AuthorRepository authorRepository;
private AuthorCreateServiceImpl authorCreateServiceImpl;
private Author firstAuthor;
private Author secondAuthor;
#BeforeClass
public void setUp() {
authorCreateServiceImpl = new AuthorCreateServiceImpl(authorRepository);
firstAuthor = new Author();
firstAuthor.setFirstName("Leo");
firstAuthor.setLastName("Manly");
firstAuthor.setNationality("Mexico");
firstAuthor.setId(3L);
secondAuthor = new Author();
secondAuthor.setFirstName("Zorro");
secondAuthor.setLastName("Plata");
secondAuthor.setNationality("Zambia");
secondAuthor.setId(4L);
}
#Test
public void succesfullySaveAuthorTest() {
Author testAuthor = authorCreateServiceImpl.create(firstAuthor);
Assert.assertEquals(testAuthor.getFirstName(), firstAuthor.getFirstName());
}
#Test
public void failSavingAuthorTest() {
String firstName = "Man";
Author testAuthor = authorCreateServiceImpl.create(secondAuthor);
boolean isEqual = testAuthor.getFirstName().equals(firstName);
Assert.assertFalse(isEqual);
}
}
In this state testAuthor is null, but repository and createService objects exist. But if I add an Autowired annotation to the AutrhorCreateServiceImpl field, it works fine.
Is the Autowired necessary or I'm doing something wrong?
EDIT
TestConfiguration class
#ComponentScan(basePackages = {"com.altkom.library"} )
#Configuration
#TestPropertySource(locations = "classpath:test.properties")
public class TestConfiguration extends JPAConfiguration {
public TestConfiguration(Environment environment) {
super(environment);
}
#Bean(destroyMethod = "shutdown")
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
EmbeddedDatabase dataBase = builder.setType(EmbeddedDatabaseType.H2).addScript("classpath:import.sql").build();
return dataBase;
}
}
If you want to obtain bean from spring-context, this annotation is required.
In your implementation you've created a service with a mocked repository. Mocked objects return null by default. You can use Mockito.when() to override default behaviour.