I would like to inject a FileInputStream as a constructor argument using spring annotation.
Lets say I have the following class (before doing constructor arg injection)
#Component
public class MyClass{
private BlaClass xy;
public MyClass(InputStream is)
{
this.xy = new BlaClass(is);
}
}
So now my question is if I can use the #Value annotation or a similar one in order to inject the input stream? Should be something like this:
#Component
public class MyClass{
private BlaClassTakingAnInputStream xy;
//this is of course not correct
public MyClass(#Value("classpath:path/to/a/file") is)
{
this.xy = new BlaClassTakingAnInputStream(is);
}
}
p.s.: I know how it works using xml configuration but I would like to do it using annotations since its less verbose.
You can use a Resource like so
#Autowired
public MyClass(#Value("classpath:path/to/a/file") Resource resource) {
// access to resource input stream
}
Note that the #Autowired is required to mark this constructor as the one to use. Otherwise, Spring would look for a parameterless constructor.
Related
I have application.yml that looks like this:
feature:
toggles:
checksLoginAndRegistration: true
I am trying to get it in my class with #Value annotation, but it's not working.
public class UMLUserRepository implements UserRepository {
#Value("${feature.toggles.checksLoginAndRegistration}")
private boolean checksLoginAndRegistration;
private void validateLoginNow(LoginInfo info, User user) {
checkKnownBlock(info, user.username);
if(checksLoginAndRegistration){
try {
service.validateLogin(user.username);
} catch (ValidationException alidationException) {
throw new Exception(user.username);
}
}
}
When I debug the code my checksLoginAndRegistration variable is set to false.
According to the comments you have used #Value annotation within a simple POJO. Not inside a Spring Bean like #Component, #Service or #Configuration.
You cannot inject a value to a POJO class using #Value.
This annotation can be used for injecting values into fields in Spring-managed beans, and it can be applied at the field or constructor/method parameter level.
But still you get value false for checksLoginAndRegistration parameter because it is an primitive type which has a default value false. If you chaged it to boxed type Boolean you can see the value of checksLoginAndRegistration is null
Update
#ConfigurationProperties(prefix = "feature.toggles")
public class AppConfig {
private Boolean checksLoginAndRegistration;
}
Then update your UMLUserRepository class, (We make checksLoginAndRegistration is a dependency to UMLUserRepository class)
public class UMLUserRepository implements UserRepository {
private final Boolean checksLoginAndRegistration;
public UMLUserRepository(Boolean checksLoginAndRegistration) {
this.checksLoginAndRegistration = checksLoginAndRegistration;
}
}
This is the class where you crate instance of UMLUserRepository class. An it should be a Spring Bean.
#Component (or #Service)
public class ClassYouInitatingUMLUserRepository {
#Autowire
private AppConfig appConfig;
public void yourMethod() {
UMLUserRepository repo = new UMLUserRepository(appConfig.getChecksLoginAndRegistration());
}
I would encourage you to check the possibility to convert UMLUserRepository class to a Spring bean. Then this won't be needed.
Hmm, it seems like you do everything correctly. I can suggest what can go wrong
Is it all what file contains?
If not, check is there only one feature key or not. If there's another one, remove it.
Have you added #Configuration annotation to your configuration class?
If not, add it.
In one of my controller
#Autowired
private Map<String, ABC> abcMap;
now I want mock it in one of the unit test but I always get null pointer exception.
This map contains implementations of ABC abstract class.
Can anyone suggest a possible solution?
I'm not sure what Unit test Framework you are using but there are ways of making it inject the mock details. You'll have to give us more information before before we can answer.
Personally I don't much like Autowired private fields, so at the risk of answering a different question can I suggest you consider using an Autowired constructor instead. From Springs POV it won't make a difference, your object will be create and all the appropriate data wired in. (OK, there is a slight change in the order things are done, but generally you won't notice). You will have to write a constructor to copy the constructor parameters to private fields, but:
Those fields could be made final, which could make your class safer
Your Unit tests wont need any 'magic' to initialise the Autowired fields - just pass parameters
If you refactor you class to remove add/remove/modify an Autowired field then you have to remember to change your test code. With an Autowired constructor you test code has to be changed or it won't compile, and your IDE might even help you do it.
Update
The Autowired constructor alternative looks something like:
#Controller
class MyClass {
private final Class1 bean1;
private final Object value2;
#Autowired
MyClass(Class1 bean1, Class2 bean2) {
this.bean1 = bean1;
this.value2 = bean2.getValue();
}
}
Keys points are:
The class has just one constructor and it requires parameters.
The fields are not annotated #Autowired, because Spring is not assigning values to them; the constructor does that.
The constructor IS annotated as #Autowired to tell Spring to pass the beans as parameters
The first parameter is stored in a final variable - you code can't accidentally over write it, so your code is safer
In my example the second parameter is only used in the constructor, so we don't have to store it as a field in your controller. I often to this if the Bean is an object that passes configuration around.
A No-argument constructor is not required
At test time your code will have to pass parameters to the class.
Your test code will look something like:
class MyClassTest {
private Class1 bean1;
private Class2 bean2;
private MyClass objectUnderTest;
#Before
public void setUp() throws Exception {
bean1 = mock(Class1.class);
bean2 = mock(Class2.class);
// Train mocks here
objectUnderTest = new MyClass(bean1, bean2)
}
#Test
public void myTest() {
// Do something with objectUnderTest
}
}
Key points are:
There are no #MockBean annotations
The Unit test is only using the API that your Controller bean defines; No black magic is required
It's not possible to create a MyClass with out providing the required data. This is enforced by the compiler
I think you can try it.
The sample of code:
public interface Animal {
}
#Service
public class Cat implements Animal{
}
#Service
public class Dog implements Animal{
}
#Service
public class Clinic {
#Autowired
private final Map<String, Animal> animalMap = new HashMap<>(2);
}
Sample of test
#Configuration
public class TestEnvConfig {
#Bean
public Clinic create(){
return new Clinic();
}
#MockBean // you can do it without mock or use #ComponentScan
Dog dog;
#MockBean
Cat cat;
}
#SpringBootTest(classes = TestEnvConfig.class)
#RunWith(SpringRunner.class)
public class ClinicTest {
#Autowired
private Clinic clinic;
}
I defined some interfaces with generic, and I have some classes injected in Spring context as Beans, could I dynamic create a manager bean to manage them, and it could be autowired in fields without any Bean def code of this manager?
I have tried FactoryBean way to implement it, but not worked, it couldn't transmit generic class info and the FactoryBean bean couldn't transmit any changable arguments.
I have tried BeanFactory way to implement it, when I getBeansOfType, these objects created without autowired, not worked...
Now I have a finally method which I think it's not very smart that is using ImportBeanDefinitionRegistrar and ClassPathBeanDefinitionScanner to scan all classes, then insert the manager's beanDefinition.
I'll be very appreciate if you supply any method, Thank you very much !
I want to implement it like this:
public interface Strategy<E extends BaseEnum>
{
public E getType();
}
public interface LoginStrategy extends Strategy<LoginType>
{
public LoginStrategy getType();
}
#Strategy
public class ALoginStrategy implements LoginStrategy
{
public getType()
{
return LoginType.OTP;
}
}
#Strategy
public class BLoginStrategy implements LoginStrategy
{
#Autowired
private UserMapper;
public getType()
{
return LoginType.PASSWORD;
}
}
public LoginServiceImpl implements LoginService
{
#Autowired
private StrategyManage<LoginType, LoginStrategy> strategyManager;
}
I want the strategyManager in LoginServiceImpl which is marked Autowired could be auto generated.
I also have a other question. It may be easier to explain what I want.
I have a model convertor implements a ModelConvertor interface, TL is lowerModel's class, TU is upperModel's class.
now there is a bean include code like this:
#Autowired
private ModelConvertor<UserPO, UserDO> userConvertor;
normally Spring frame would throw a Exception with a "no such bean" message, so I want to make this field could auto inject a value like this:
#Autowired
private ModelConvertor<UserPO, UserDO> userConvertor[ = new DefaultModelConvertor(UserPO.class, UserDO.class)];
How can I do to solve these problems, thanks a lot again!
I have resolved this problem, scan specific packages and dynamic generate beans to put on context.
I'm new to Java Spring and trying to use Java configuration and inject a dependency into a class constructor. I want to use constructor injection because the class methods require the dependency. It isn't working for me.
Use case: Create a JSON string from a Java object and validate it before returning.
Class: FakeJsonBuilder
Dependency: JsonValidator
Main class: Per Spring documentation the #SpringBootApplication annotation is a convenience annotation that adds #Configuration, #EnableAutoConfiguration and #ComponentScan so I should be good to go as far as dependency injection is concerned.
#SpringBootApplication
public class MySpringApplication {
public static void main(String[] args){
// Register the class we use for Java based configuration
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext();
context.register(ApplicationConfiguration.class);
context.refresh();
SpringApplication.run(MySpringApplication .class, args);
}
}
Java configuration class:
#Configuration
public class ApplicationConfiguration {
#Bean
public JsonValidator jsonValidator(){
return new JsonValidatorImpl();
}
#Bean
public JsonBuilder(){
return new FakeJsonBuilder();
}
}
FakeJsonBuilder class:
public class FakeJsonBuilder implements JsonBuilder{
private static Log logger = LogFactory.getLog(FakeJsonBuilder.class);
private static JsonValidator jsonValidator;
// I need an empty constructor for the ApplicationConfiguration setup to work.
public MlrModelJsonBuilder(){};
#Autowired
public FakeJsonBuilder (JsonValidator jsonValidator){
this.jsonValidator = jsonValidator;
boolean validatorInjected = (jsonValidator != null);
logger.info("Validator injected: " + validatorInjected);
}
.......... More methods
The jsonValidator dependency is not being injected, i.e. the log message is Validator injected: false
Quoting Martin: Fowler http://martinfowler.com/articles/injection.html
"My long running default with objects is as much as possible, to create valid objects at construction time. This advice goes back to Kent Beck's Smalltalk Best Practice Patterns: Constructor Method and Constructor Parameter Method. Constructors with parameters give you a clear statement of what it means to create a valid object in an obvious place. If there's more than one way to do it, create multiple constructors that show the different combinations."
I come from a .NET background and use Ninject to inject my dependencies into the class constructor for the reasons Fowler gives. I quoted Fowler because of his credibility but you will find many sources providing the same argument, i.e. if the class methods require the dependency then it should be injected into the constructor. So here's how I figured how to do it with Java Spring (I revert to my C# syntax - forgive the transgression):
The configuration class
#Configuration
public class ApplicationConfiguration {
#Bean
public IJsonValidator jsonValidator(){
return new JsonValidator();
}
#Bean
public IJsonBuilder jsonBuilder(){
return new JsonBuilder(jsonValidator());
}
}
The class into which we inject the dependency
public class JsonBuilder implements IJsonBuilder {
private static IJsonValidator _jsonValidator;
// #Autowired // not needed per Sotirios. tested and verified
public JsonBuilder(IJsonValidator jsonValidator) {
_jsonValidator = jsonValidator;
}
public String getFoobar() {
// Returns false. jsonValidator was injected
boolean foo = (_jsonValidator == null);
return "Validator was injected: " + foo;
}
... more methods
I am studying for the Spring Core certification and I have the following doubt related how can Spring instantiate classes with private constructors (such as Singleton pattern) or how can instantiate objects from Factories (that are not the Spring context).
For example I have the following singleton factory:
public class AccountServiceSingleton implements AccountService {
private static AccountServiceSingleton inst = new AccountServiceSingleton();
private AccountServiceSingleton() { ... }
public static AccountService getInstance() {
// ...
return inst;
}
}
This is a singleton factory because it build a private static object builded with a private constructor and I have a public method to get this object.
So I think that the problem how can Spring build this object? depends on the fact that that the constructor is private so I can't do something like this in my Java configuration class
#Confguration
public class ApplicationConfig{
#Bean
public AccountServiceSingleton accountServiceSingleton(){
return new AccountServiceSingleton();
}
}
because I can't access to the private AccountServiceSingleton() constructor.
At the same time I can't use the equivalent XML configuration for the same reason.
Have I understand what is the problem or am I missing something?
I think that I am missing something because on the documentation I read that I can use the following 2 solutions for the previous problem:
Use a #Bean method in #Configuration class: so, reading it, I think that the previous Java configuration class work...but why?
XML factory-method attribute in the XML configuration, searching online I found that have to be something like this, but how can I use this to configure the previous AccountServiceSingleton bean in an XML configuration?
Tnx
It's really easy, and you can do it, too:
Constructor cxor = AccountServiceSingleton.class.getDeclaredConstructor();
cxor.setAccessible(true);
return cxor.newInstance();
I found the answer by myself still reading the documentation. I think that the right answer for the question is:
If I want to configure this class as a Spring bean:
public class AccountServiceSingleton implements AccountService {
private static AccountServiceSingleton inst = new AccountServiceSingleton();
private AccountServiceSingleton() { ... }
public static AccountService getInstance() {
// ...
return inst;
}
}
using the Java configuration I simply have to annotate the relative bean method using #Bean in the configuration class.
If I want configure the beans using the XML configuration I have to use the factory method attribute, something like it:
<bean id=“accountService” class=“com.acme.AccountServiceSingleton”
factory-method="getInstance" />
So it say that the getInstance() method will be call to obtain the singleton object from my singleton factory
How about doing like this:
#Confguration
public class ApplicationConfig{
#Bean
public AccountServiceSingleton accountServiceSingleton(){
return AccountServiceSingleton.getInstance();
}
}