I can not inject Map<String, String> from YAML file - spring-boot

I have this properties in my YAML file:
request-topic:
topics:
IMPORT_CHARGES: topic-name-1
IMPORT_PAYMENTS: topic-name-2
IMPORT_CATALOGS: topic-name-3
And this class:
#Getter
#Setter
#Component
#ConfigurationProperties(prefix = "topic-properties")
public class TopicProperties {
private Map<String, String> topics = new HashMap<>();
public String getTopicNameByType(String type){
return topics.get(type);
}
}
But when I autowire this properies I get empty Map:
#Service
public class TopicRouterImpl implements TopicRouter {
private final TopicProperties topics;
public TopicRouterImpl(TopicProperties topics) {
this.topics = topics;
}
#PostConstruct
public void init(){
topics.getTopicNameByType("IMPORT_CHARGES");
}
#Override
public String getTopicName(MessageType messageType) {
return topics.getTopicNameByType(messageType.name());
}
}

This is due to the name mismatch in your yaml file it should be equals to the specified prefix : topic-properties. Like this :
topic-properties:
topics:
IMPORT_CHARGES: topic-name-1
IMPORT_PAYMENTS: topic-name-2
IMPORT_CATALOGS: topic-name-3

Related

Spring Boot #ConfigurationProperties

so I'm kinda new to Springboot and I'm trying to get the value from application.properties. I want to get multiple value from the application.properties and insert it into a list. At first, I tried to get the value from controller class and it works. Now I tried to get the value from a new class, but the value won't show up and it's showing an error because it says that it's null. Am i missing an annotation or did i do something wrong in the code? Below is my code.
application.properties:
example.name[0] = asdf
example.name[1] = qwer
List Value class:
#ConfigurationProperties(prefix = "example")
#Configuration
public class NameProperties {
private List<String> name;
public List<String> getName() {
return name;
}
public void setName(List<String> name) {
this.name = name;
}
}
What i tried in controller and worked:
#RestController
#CrossOrigin
#RequestMapping("/tes/**")
public class NameController {
#Autowired
NameProperties property = new NameProperties();
#GetMapping
public String tes() {
String name = property.getName().get(0);
System.out.println(name);
return name;
}
}
In the new class that doesn't work:
#Component
public class NameConfiguration {
#Autowired
NameProperties property = new NameProperties();
public void getName(int index) {
System.out.println(property.getName().get(0));
}
}
The code to test the new class in the controller:
#RestController
#CrossOrigin
#RequestMapping("/tes/**")
public class NameController {
NameConfiguration conf = new NameConfiguration();
#GetMapping
public String tes() {
conf.getName(0);
}
}
Is it because the value doesn't get injected when I call the class or what should I do? Appreciate any kind of help. Thanks!
Hello friend when you declare your class as a Spring Bean you shouldn't initialize the object yourself other the properties define in it will not be injected by Spring, so you should let spring help you with that, try these class below
NameProperties
#Component
#ConfigurationProperties(prefix = "example")
public class NameProperties {
private List<String> name;
public List<String> getName() {
return name;
}
public void setName(List<String> name) {
this.name = name;
}
}
NameConfiguration.java
#Component
public class NameConfiguration {
#Autowired
NameProperties property;
public void getName(int index) {
System.out.println(property.getName().get(0));
}
}

Mongo Template querying the wrong collection

I have a mongodb springboot application that is connected to 2 different databases, that have the same collection names and database names but different uris.
Here is my application.properties
spring.data.mongodb.uri = uri
spring.data.mongodb.secondDB.uri = uri
spring.data.mongodb.database = database_name
spring.data.mongodb.secondDB.database = database_name
My AppConfiguration file
#Configuration
public class MultipleMongoConfig {
#Primary
#Bean(name = "newdb1Properties")
#ConfigurationProperties(prefix = "spring.data.mongodb")
public MongoProperties getNewDb1Props() throws Exception {
return new MongoProperties();
}
#Bean(name = "newdb2Properties")
#ConfigurationProperties(prefix = "spring.data.mongodb.secondDB")
public MongoProperties getNewDb2Props() throws Exception {
return new MongoProperties();
}
#Primary
#Bean(name = "newdb1MongoTemplate")
public MongoTemplate newdb1MongoTemplate() throws Exception {
return new MongoTemplate(newdb1MongoDatabaseFactory(getNewDb1Props()));
}
#Bean(name ="newdb2MongoTemplate")
public MongoTemplate newdb2MongoTemplate() throws Exception {
return new MongoTemplate(newdb2MongoDatabaseFactory(getNewDb2Props()));
}
#Primary
#Bean
public MongoDatabaseFactory newdb1MongoDatabaseFactory(MongoProperties mongo) throws Exception {
return new SimpleMongoClientDatabaseFactory(
mongo.getUri()
);
}
#Bean
public MongoDatabaseFactory newdb2MongoDatabaseFactory(MongoProperties mongo) throws Exception {
return new SimpleMongoClientDatabaseFactory(
mongo.getUri()
);
}
Then I set up config files for each data source
#Configuration
#EnableMongoRepositories(basePackages = {"com.example.app.firstDatabse.Repository"},
mongoTemplateRef = "newdb1MongoTemplate"
)
public class NewDb1Config {
}
and
#Configuration
#EnableMongoRepositories(basePackages = {"com.example.app.secondDatabse.Repository"},
mongoTemplateRef = "newdb2MongoTemplate"
)
public class NewDb1Config {
}
For Model I have the following
#AllArgsConstructor
#NoArgsConstructor
#ToSting
#Document(collection = "coll")
public class FirstModel{
#Id
public String id;
#Field("f_name")
public String firstName;
#Field("l_name")
public String lastName;
#Field("age")
public int age;
#Field("gender")
public String gender;
}
and my second Model is the same
#AllArgsConstructor
#NoArgsConstructor
#ToSting
#Document(collection = "coll")
public class SecondModel{
#Id
public String id;
#Field("f_name")
public String firstName;
#Field("l_name")
public String lastName;
#Field("age")
public int age;
#Field("gender")
public String gender;
}
My controller
#ResController
#RequestMapping("/controller")
public class Controller{
#Autowired
private FirstDataabseRepository repo;
#Autowired
private SecondDataabseRepository repo;
#Resource
private MongoTemplate mongoTemplate;
#RequestMapping("/findByName")
public List<SecondModel> findByName(){
Criteria criteria = new Criteria();
criteria = Criteria.where("f_name").is("John");
Query q = new Query(criteria);
List<SecondModel> results = mongoTemplate.find(q,SecondModel.class);
return results;
}
}
So the results show the results of the first collection not the second one. What do I need to do for mongoTemplate to query the second collection not the first one.
Solution
I have to add a qualifier and have a mongoTemplate for each collection
#ResController
#RequestMapping("/controller")
public class Controller{
#Autowired
private FirstDataabseRepository repo;
#Autowired
private SecondDataabseRepository repo;
#Resource
#Qualifier(value="newdb1MongoTemplate")
private MongoTemplate mongoTemplate;
#Resource
#Qualifier(value="newdb2MongoTemplate")
private MongoTemplate mTemplate;
#RequestMapping("/findByName")
public List<SecondModel> findByName(){
Criteria criteria = new Criteria();
criteria = Criteria.where("f_name").is("John");
Query q = new Query(criteria);
List<SecondModel> results = mTemplate.find(q,SecondModel.class);
return results;
}
}

spring inject templated class object

#Component
public class A<K, V> {
#Autowired
// spring unable to inject this, #Qualifier can not use here
private B<K, V> b;
}
public class B<K, V>{}
#Configuration
public class ConifgA {
#Bean
#Qualifier("int_a")
public A<Integer, Integer> getA1() { return new A<>(); }
#Bean
#Qualifier("int_a")
public A<String, String> getA2() { return new A<>(); }
}
#Configuration
public class ConifgB {
#Bean
public B<Integer, Integer> getB1() { return new B<>(); }
#Bean
public B<String, String> getB2() { return new B<>(); }
}
#Component
class C {
#Autowired
#Qualifier("int_a")
A<Integer, Integer> ia;
#Autowired
#Qualifier("str_a")
A<String, String> sa;
}
I can not manually new B() and pass it to A's ctor because B contains data members which was injected by spring
#Qualifier is typically used paired with #Autowired to specify a single bean candidate by name when there are several bean instances with shared interface in the context. If you wish to inject a desired bean name, just setting the default value in #Bean works.
I've written a test class that works for your scenario:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = FooTest.TestConfig.class)
public class FooTest {
#Autowired
private C c;
#Test
public void testCisAvailable(){
Assert.assertNotNull(c);
}
#Configuration
static class TestConfig {
#Bean("int_a")
public A<Integer, Integer> getA1(B<Integer, Integer> b) {
return new A<>(b);
}
#Bean("str_a")
public A<String, String> getA2(B<String, String> b) {
return new A<>(b);
}
#Bean
public B<Integer, Integer> getB1() {
return new B<>();
}
#Bean
public B<String, String> getB2() {
return new B<>();
}
#Bean
public C getC(A<Integer, Integer> ia,
A<String, String> sa) {
return new C(ia, sa);
}
}
static class B<K, V> {
}
static class A<K, V> {
private final B<K, V> b;
#Autowired
public A(B<K, V> b) {
this.b = b;
}
}
static class C {
private final A<Integer, Integer> ia;
private final A<String, String> sa;
#Autowired
public C(#Qualifier("int_a") A<Integer, Integer> ia,
#Qualifier("str_a") A<String, String> sa) {
this.ia = ia;
this.sa = sa;
}
}
}

Jersey 2.13 + Bean Validation

I'm using gradle and the following libs:
ext.library['jersey'] = "org.glassfish.jersey:project:2.13"
ext.library['jersey_jettison'] = "org.glassfish.jersey.media:jersey-media-json-jettison:2.13"
ext.library['jersey_jackson'] = "org.glassfish.jersey.media:jersey-media-json-jackson1:2.13"
ext.library['jersey_spring'] = "org.glassfish.jersey.ext:jersey-spring3:2.13"
ext.library['jersey_bean_validation'] = "org.glassfish.jersey.ext:jersey-bean-validation:2.13"
I created the bean validation structure, but its not validating at all. No error messages, nothing. This is the structure I've created:
The DTO
public class MergeSchedulesDto {
#NotNull(message = "validation.invalid.mergeFrom")
private Long mergeFrom;
#NotNull(message = "validation.invalid.mergeTo")
#NotEmpty(message = "validation.invalid.mergeTo")
private List<Long> mergeTo;
The Service
#Path("merge")
#POST
#Consumes({ MediaType.APPLICATION_JSON })
public Response merge(#Valid MergeSchedulesDto dto, #QueryParam("units") List<Long> units) {
The config
public class ApplicationJAXRS extends Application {
public ApplicationJAXRS() {
}
#Override
public Map<String, Object> getProperties() {
Map<String, Object> properties = new HashMap<>();
properties
.put("jersey.config.server.provider.packages",
"com.sifionsolution.sig.academic.resource.service,com.sifionsolution.sig.integration.resource.filter,com.sifionsolution.sig.academic.param.converter,com.sifionsolution.sig.datatables.resource.service,com.sifionsolution.sig.datatables.converter");
return properties;
}
#Override
public Set<Object> getSingletons() {
Set<Object> singletons = new HashSet<>();
singletons.add(new Jackson1Feature());
singletons.add(new ValidationExceptionMapper());
return singletons;
}
}
EDIT I forgot the provider:
#Provider
public class ValidationExceptionMapper implements ExceptionMapper<ConstraintViolationException> {
#Override
public Response toResponse(ConstraintViolationException exception) {
return Response.status(BAD_REQUEST).entity(exception.getMessage()).build();
}
}
EDIT 2: I removed the JUnit test because I didnt test using Jersey Test Framework.
The problem here is that the ValidationExceptionMapper is not beeing called.
Put "#Valid" in your, like this:
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response insert(#Valid T obj) throws Exception{
...
}
This works here.

Spring MongoRepository is Null

I have the following code which attempts to save a POJO object (Actor) into MongoDB using Spring Mongo Repository, but the repository object is always Null. I have followed multiple examples but mainly this one
The POJO class:
#Document(collection = "actors")
public class Actor
{
#Id
private String id;
...
//constructor
//setters & getters
}
The repository:
public interface ActorRepository extends MongoRepository<Actor, String>
{
public Actor findByFNameAndLName(String fName, String lName);
public Actor findByFName (String fName);
public Actor findByLName(String lName);
}
The service that uses the repository:
#Service
public class ActorService
{
#Autowired
private ActorRepository actorRepository;
public Actor insert(Actor a)
{
a.setId(null);
return actorRepository.save(a);
}
}
And I access the service from a REST controller class:
#RestController
public class Controllers
{
private static final Logger logger = Logger.getLogger(Controllers.class);
private static final ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringMongoConfig.class);
private ActorService actorService = new ActorService();
#RequestMapping(value="/createActor", method=RequestMethod.POST)
public #ResponseBody String createActor(#RequestParam(value = "fName") String fName,
#RequestParam(value = "lName") String lName,
#RequestParam(value = "role") String role)
{
return actorService.insert(new Actor(null,fName,lName,role)).toString();
}
...
}
The error that I get is NullPointerException from this line: return actorRepository.save(a); in the ActorService.insert() method.
Any Idea why is this happening?
EDIT: Here is the Spring Configurations
#Configuration
public class SpringMongoConfig extends AbstractMongoConfiguration
{
#Bean
public GridFsTemplate gridFsTemplate() throws Exception
{
return new GridFsTemplate(mongoDbFactory(), mappingMongoConverter());
}
#Override
protected String getDatabaseName()
{
return "SEaaS";
}
#Override
#Bean
public Mongo mongo() throws Exception
{
return new MongoClient("localhost" , 27017 );
}
public #Bean MongoTemplate mongoTemplate() throws Exception
{
return new MongoTemplate(mongo(), getDatabaseName());
}
}
The problem is that you are not using Spring to get the ActorService dependency -instead you have manually instantiated the dependency using
private ActorService actorService = new ActorService();.
The following code is the easiest fix in order to inject the ActorService dependency into the controller.
#RestController
public class Controllers
{
private static final Logger logger = Logger.getLogger(Controllers.class);
private static final ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringMongoConfig.class);
#Autowired
private ActorService actorService;
#RequestMapping(value="/createActor", method=RequestMethod.POST)
public #ResponseBody String createActor(#RequestParam(value = "fName") String fName,
#RequestParam(value = "lName") String lName,
#RequestParam(value = "role") String role)
{
return actorService.insert(new Actor(null,fName,lName,role)).toString();
}
...
}

Resources