Reading application.properties from any class in spring boot - properties

When I add a property in the application.properties files, this can be access from the main class without any problem.
#SpringBootApplication
#ComponentScan(basePackages = "com.example.*")
public class MailTestApplication implements CommandLineRunner {
#Value("${admin.mail}")
String email;
public static void main(String[] args) {
SpringApplication.run(MailTestApplication.class, args);
}
#Override
public void run(String... strings) throws Exception {
System.out.println(email);
Email email = new Email();
email.sendMail();
}
}
However, when I try to access it from any other class it is never retrieved.
#Component
public class Email {
#Autowired
private MailSender sender;
#Value("${admin.mail}")
String email;
public Email() {
}
public void sendMail() {
SimpleMailMessage msg = new SimpleMailMessage();
System.out.println(email);
msg.setTo("sample#email.com");
msg.setSubject("Send mail by Spring Boot");
msg.setText("Send mail by Spring Boot");
sender.send(msg);
}
}
I was reading some of the previous questions other users posted without a clear result for me. I even tried to find some examples with similar resutl.
Could someone give me any clue about this?
Thanks a lot in advance.

The #Value should work (Im asuming your class is under the com.example.* package since you are scanning that package) but if you want to do it another way this is what im using :
public class JpaConfiguration {
public static final String TRANSACTION_MANAGER_NAME = "jpaTransactionManager";
#Autowired
Environment applicationProperties;
Then to use it
#Bean
public DriverManagerDataSource driverManagerDataSource() {
DriverManagerDataSource driverConfig = new DriverManagerDataSource();
driverConfig.setDriverClassName(applicationProperties.getProperty("data.jpa.driverClass"));
driverConfig.setUrl(applicationProperties
.getProperty("data.jpa.connection.url"));
driverConfig.setUsername(applicationProperties
.getProperty("data.jpa.username"));
driverConfig.setPassword(applicationProperties
.getProperty("data.jpa.password"));
return driverConfig;
}
UPDATE AFTER GETTING THE GITHUB REPO
I Don't really know what you are trying to build but :
If you do this:
#Override
public void run(String... strings) throws Exception {
//System.out.println(email);
Email email = new Email();
email.sendMail();
}
Then you are creating the instance of the class, and not spring. so you shouldn't be creating the instance yourself there it should be spring.
That said, i dont know if you are creating a web application a command line application or both.
That said ill give you a minor solution to show you that the dependency injection is in fact working.
1_ add a getter to your email on email class. remove the CommandLine interface (If you want to implement this i would recomend you to put CommandLine implmentations on another package say Controller);
And then run your app like this:
#SpringBootApplication
#ComponentScan(basePackages = "com.example")
public class MailTestApplication {
#Value("${admin.mail}")
String email;
public static void main(String[] args) {
// SpringApplication.run(MailTestApplication.class, args);
final ConfigurableApplicationContext context = new SpringApplicationBuilder(MailTestApplication.class).run(args);
Email e = context.getBean(Email.class);
System.out.println(e.getEmail());
}
The Key thing I want to show is that the instance is created by spring thats why the wiring works. and the email gets printed in the console.
Regarding the email class :
#Component
public class Email {
// #Autowired
// private MailSender sender;
#Value("${admin.mail}")
String email;
public Email() {
}
public void sendMail() {
SimpleMailMessage msg = new SimpleMailMessage();
System.out.println(email);
msg.setTo("sample#email.com");
msg.setSubject("Send mail by Spring Boot");
msg.setText("Send mail by Spring Boot");
// sender.send(msg);
}
public String getEmail() {
return email;
}
}
I Comment out the MailSender since I think you need to configure that too, i have made a custom mailSender that uses gmail and other for mailChimp that i can share with you if you need. but again I dont really know what your intent with the app is.
Hope the info helps you.

Related

Why WebApplicationFactory is saving state from previous builds?

I will try to show my problem with a sample code easier to understand.
I have used WebApplicationFactory to develop my acceptance tests. Let's say that I have the typical minimal Program.cs with the following line to register one of my modules:
builder.Services.RegisterModule<StartupRegistrationModule>(builder.Configuration, builder.Environment);
And this module is declared like this:
internal sealed class StartupRegistrationModule : IServiceRegistrationModule
{
public static Dictionary<string, string> _dictionary = new();
public void Register(IServiceCollection services, IConfiguration configuration, IHostEnvironment hostEnvironment)
{
// Lot of modules being registered
_dictionary.Add("key", "value");
}
}
One of my tests file is like this:
public sealed class MyTests : AcceptanceTestBase
{
[Fact]
public void Test1()
{
// arrange
// act
// assert
}
[Fact]
public void Test2()
{
// arrange
// act
// assert
}
[Fact]
public void Test3()
{
// arrange
// act
// assert
}
}
And AcceptanceTestBase is:
public abstract class AcceptanceTestBase : IDisposable
{
protected HttpClient _httpClient;
protected WebApplicationFactory<Program> _webApplicationFactory;
public AcceptanceTestBase()
{
_webApplicationFactory = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder =>
{
// ... Configure test services
});
_httpClient = _webApplicationFactory.CreateClient();
}
public void Dispose()
{
_httpClient.Dispose();
_webApplicationFactory.Dispose();
}
}
If I try to execute all these tests my tests will fail in the second test run because the WebApplicationFactory is trying to build again the Application but it already has the key in the dictionary and it will fail. See the image for more understanding on the problem.
So my question is, how can I build the application in different scopes to do not share this dictionary state?
Thanks :)
Update:
The real static dictionary is saved behind this nuget package that keeps the track of all my circuit breaker policies state. I do not actually need even the HttpClients for my tests but did not find a way to remove them and not load this. I tried removing all the HttpClients to see if it also removes their dependencies, but it does not seem to make the trick.
It is because you are using:
internal sealed class StartupRegistrationModule : IServiceRegistrationModule
{
/// .. static here
public static Dictionary<string, string> _dictionary = new();
public void Register(IServiceCollection services, IConfiguration configuration, IHostEnvironment hostEnvironment)
{
// Lot of modules being registered
_dictionary.Add("key", "value");
}
}
The static Dictionary is shared over all your tests because they run in the same process.
Each test starts a new (Test-)WebHost but the dictionary remains untouched.
My proposal is to not use statics anywhere in DI context to prevent such hidden traps.
I don't know the purpose of your Dictionary here but maybe you can extract this to a singleton registration which you can replace in your (Test.)WebHost on each new test / startup?

Cling: Looking for Opensource code for uPnp ContentDirectory

I'm trying to build a uPnP control point for controlling audio and I am using Java the cling library. To browse the music on the server requires the ContentDirectory service, cling provides the api to access this but doesnt provide any classes to represent the various actions and arguments requiring me to write lots of boilerplate code, I wonder does such a library exist ?
For example Ive create a Browse class for the Browse action of a Content Directory
import org.fourthline.cling.model.meta.Action;
import org.fourthline.cling.model.types.UnsignedIntegerFourBytes;
public class Browse extends AbstractActionAndInvocation
{
//INPUT
public static final String OBJECT_ID = "ObjectID";
public static final String BROWSE_FLAG = "BrowseFlag";
public static final String FILTER = "Filter";
public static final String STARTING_INDEX = "StartingIndex";
public static final String REQUESTED_COUNMT = "RequestedCount";
public void setObjectID(String objectID)
{
actionInvocation.setInput(OBJECT_ID, objectID);
}
public void setBrowseFlag(BrowseFlag browseFlag)
{
actionInvocation.setInput(BROWSE_FLAG, browseFlag.getParameterName());
}
public void setFilter(String filter)
{
actionInvocation.setInput(FILTER, filter);
}
public void setStartingIndex(int startingIndex)
{
actionInvocation.setInput(STARTING_INDEX, new UnsignedIntegerFourBytes(startingIndex));
}
public void setRequestedCount(int requestCount)
{
actionInvocation.setInput(REQUESTED_COUNMT, new UnsignedIntegerFourBytes(requestCount));
}
public Browse(Action action)
{
super(action);
}
}
Since ContentDirectory only has a predefined list of Actions it seems weird that these don't already exist somewhere ?
Within the cling-support module there are useful classes such as callback classes for the main services
e.g
org.fourthline.cling.support.contentdirectory.callback.Browse.java;
However I found them to be of limited usefulness and serve more as an example implementation rather than one that can be used as is.

How to access I18n Bean from inside a task

I am trying to create a plugin with a task, but I have trouble getting access to an instance of I18bean for retrieving internationalized message. Does anyone has a hint on how to do it ?
Found it. You need to add a constructor with a I18nBeanFactory parameter and use this one for retrieving an I18nBean
public class CreateFileTask implements TaskType {
public I18nBeanFactory i18nBeanFactory;
public CreateFileTask(I18nBeanFactory i18nBeanFactory) {
this.i18nBeanFactory=i18nBeanFactory;
}
#NotNull
#Override
public TaskResult execute(TaskContext taskContext) throws TaskException {
I18nBean i18nBean = i18nBeanFactory.getI18nBean();
i18Bean.getText(...);
}
}

Instantiate using Windsor's factory

Below's code is working fine, and successfully create an instance for class DummyComponnent.
But the problem arises when i had changed the factory method name CreatDummyComponnent()
to GetDummyComponnent() or anything else except Creat as the beginning of method name, say AnyThingComponent throws an exception. is there any specify naming rule for factory methods ?
using System;
using Castle.Facilities.TypedFactory;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
namespace AsFactoryImplementation
{
public interface IDummyComponnentFactory
{
IDummyComponnent CreatDummyComponnent();
// void Relese(IDummyComponnent factory);
}
public interface IDummyComponnent
{
void Show();
}
public class DummyComponnent:IDummyComponnent
{
public DummyComponnent()
{
Console.WriteLine("we are working here");
}
public void Show()
{
Console.WriteLine("just testing this for better performance");
}
}
class Program
{
static void Main(string[] args)
{
var container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IDummyComponnent>().ImplementedBy<DummyComponnent>().Named("FirstConnection"),
Component.For<IDummyComponnentFactory>().AsFactory());
var val = container.Resolve<IDummyComponnentFactory>();
var iDummy = val.CreatDummyComponnent();
iDummy.Show();
Console.WriteLine("OK its done ");
Console.ReadLine();
}
}
}
You should be able to use anything for starting the method names on the Factory, except for starting with Get.
If you start with Get it will try to resolve the component by name instead of by interface.
So what would work in your example is:
var iDummy = val.GetFirstConnection();
Good luck,
Marwijn.

Google Guice, Interceptors and PrivateModules

New poster here, hope I don't brake any rules :)
I am using PrivateModule in google-guice in order to have multiple DataSource's for the same environment. But I am having a hard time getting MethodInterceptor's to work inside the private modules.
Below is a simple test case that explains the "problem".
A simple service class would be:
interface Service {
String go();
}
class ServiceImpl implements Service {
#Override #Transactional
public String go() {
return "Test Case...";
}
}
The MyModule class would be:
class MyModule extends AbstractModule {
#Override
protected void configure() {
install(new PrivateModule() {
#Override
protected void configure() {
bind(Service.class).to(ServiceImpl.class);
bindInterceptor(
Matchers.any(),
Matchers.annotatedWith(Transactional.class),
new MethodInterceptor() {
#Override
public Object invoke(MethodInvocation i)
throws Throwable {
System.out.println("Intercepting: "
+ i.getMethod().getName());
return i.proceed();
}
});
expose(Service.class);
}
});
}
}
And the final test case:
public class TestCase {
#Inject Service service;
public TestCase() {
Guice.createInjector(new MyModule()).injectMembers(this);
}
public String go() {
return service.go();
}
public static void main(String[] args) {
TestCase t = new TestCase();
System.out.println(t.go());
}
}
You would expect the output to be:
Intercepting: go
Test Case...
But it doesn't happen, the interceptor is not used, ant only Test Case... is output.
If I bind/expose the ServiceImpl instead of the interface then it works.
Thanks in advance,
Regards,
LL
Well... I figured it out shortly after I posted the question :)
The problem is that you also need to expose() the ServiceImpl class.
So the bind/expose would be.
bind(ServiceImpl.class); // ServiceImpl annotated with #Singleton
bind(Service.class).to(ServiceImpl.class);
expose(ServiceImpl.class);
expose(Service.class);
Regards,
LL
You need to explicitly bind ServiceImpl in the private module. The problem with your existing code is that it inherits the binding for ServiceImpl from the parent module. From the PrivateModule docs,
Private modules are implemented using parent injectors. When it can satisfy their dependencies, just-in-time bindings will be created in the root environment. Such bindings are shared among all environments in the tree.
Adding this line should fix the problem:
bind(ServiceImpl.class);