I'm actually new to using Guice injector. I have a situation where I have a String variable in one class and I want to use this variable in a different class without declaring it as static . Can I know how to use Guice injector here to avoid declaring it static
public class A {
private string a;
public void Method() {
a = "abc";
}
}
public class B {
public void method2() {
String b = a;
}
}
You can bind the directly to the instance of a string using the Names annotation.
bind(String.class).annotatedWith(Names.named("PROPERTY")).toInstance("Some String");
Although a better way to do it would be to use Properties:
// Your choice of loading properties
Properties properties = getPropreties();
Names.bindProperties(binder(), properties);
Then you can use either of these with
#Inject #Named("my.property") String myProperty;
Related
I am trying to write a test for pre-existing class.
class ClassToBeTested {
private final Obj1 a;
ClassToBeTested(String anotherVariable) {
a = new Obj1(anotherVariable);
}
public void methodToBeTested() {
if(invokeSomeOtherMethod()) {
a.getAnotherVariable().doSomething();
}
}
public boolean invokeSomeOtherMethod() {
// return true or false based on some logic
}
Obj1 getObj1() {
return a;
}
}
Below is my Test Class:
class TestClass {
#Test
public void testMethod() {
ClassToBeTested x = new ClassToBeTested("someString");
ClassToBeTested spyX = spy(x);
doReturn(false).when(spyX).invokeSomeOtherMethod();
spyX.methodToBeTested();
verify(spyX, times(1)).getObj1().doSomething();
}
}
This is my understanding:
Since the obj1 is private final object which is created in the class constructor, it neither be directly accessed in the test method nor force the spyObject to use a mocked version of obj1.
Also since verify() requires mocked version of obj1, it throws me an error:
Wanted But Not invoked: x.getObj1(), however there are otherInteractions with this mock: x.invokeSomeOtherMethod()
Is my understanding wrong? What would be the way to test testMoethod()?
You seem to not understand how to do proper dependency injection. You don't need to change all your code in order to make it easier to test - just use constructor telescoping for example:
class ClassToBeTested {
private final Obj1 a;
public ClassToBeTested(String anotherVariable) {
this(new Obj1(anotherVariable));
}
ClassToBeTested(Obj1 a) {
this.a = a;
}
Done. Now you have a package-protected constructor that you can use to insert an instance of a directly. And all your other production code can stay like it is.
In other words: don't "fix" your design problems by using mocking framework tricks.
I have a Java program that should read configuration parameters from file, Like this:
java -jar myapp.jar --config config.txt ...
Once loaded, these parameters do not change and should be accessible by any class in the program.
Is it possible to make these parameters accessible from any class without explicitly adding them as parameter to constructors and methods? For example, I would like to be able to do this:
public class Main {
public static void main(String[] args){
// This list should be visible by any class
List<String> CONFIGS= readMyConfigsFromFile(args[0]);
...
}
}
public class MyClass(){
public MyClass(){
String thisConf= CONFIGS.get(0); // Do something with this conf param taken from Main.
...
}
}
public class MyOtherClass(){
public MyOtherClass(){
String thisConf= CONFIGS.get(0); // Do something with this conf param taken from Main.
...
}
}
...
Is this possible at all? And is it an advisable set up to do? If not, what is the recommended design to go about it?
(I have read similar questions but I'm still unsure if and how it is possible in the situation I described)
You could use the Singleton pattern.
To model it, I assume you have 2 fields in your configuration: a String and an integer.
public class Config {
private static Config INSTANCE;
private final String field1;
private final int field2;
public Config(String field1, int field2) {
this.field1 = field1;
this.field2 = field2;
}
public String getField1() {
return field1;
}
public int getField2() {
return field2;
}
public static Config getInstance() {
if (INSTANCE == null) {
INSTANCE = loadInstance();
}
return INSTANCE;
}
private static Config loadInstance() {
// read your config from properties
String field1 = ...
int field2 = ...
return new Config(field1, field2);
}
}
And then use Config.getInstance() everywhere you need to get that instance.
Please note that this implementation has a flaw: it may be initialized several times if getInstance() gets called from different theads.
Double-checked locking https://en.wikipedia.org/wiki/Double-checked_locking may be used to overcome this flaw if it is important to you to only initialize once.
This solution, like others, would require a mock object to unit test. But I think it's best as it encapsulates the arguments in an immutable object. This also makes thread-safety a non-issue. Use a HashMap instead of an array to access these by key instead of index if you prefer:
public class Main {
public static void main(String[] args){
new CONFIG(readMyConfigsFromFile(args[0]).toArray());
...
}
public static final class CONFIG {
private final String[] args;
private static final CONFIG instance;
private CONFIG(String[] args) {
this.args = args;
instance = this;
}
public static CONFIG getInstance() {
return CONFIG.instance;
}
public String[] getArgs(){
return Arrays.copy(this.args, this.args.length);
}
public String getArg(int index) {
return args[index];
}
}
To get arguments:
Main.CONFIG.getArgs();
"Is this possible at all?". Yes, it is. You can easily do it with the help of static in java
public class Config {
private static final List<String> config = new ArrayList<String>();
public static void addConfig(String value){
config.add(value);
}
public static List<String> getConfig(){
return config;
}
}
To add values to config you can do
public static void main(String[] args) {
//Read value from file here in some variable say configValue
Config.addConfig(configValue);
}
To access config
public class MyOtherClass(){
public MyOtherClass(){
Config.getConfig().get(0); // Do something with this conf param taken from Main.
...
}
}
Note above code is not thread safe. You can make it thread safe by adding synchronization concepts
Now "And is it an advisable set up to do?". It depends on your requirements. As you mentioned these values does not change runtime then you can use this. But is the requirement we need to enforce that these values "should not change" once initialized then answer will be different and you should use something like Singleton Pattern and modify to make sure you can only read and not write once the object is constructed. Also note that with static methods, like I suggested, testing becomes really hard.
In my project, more than 1000 bean class are their. I need set the data to those classes using setter method or constructor for creating object.
I am using spring to create object. using the below code. I can create an object.
Object obj = (Object) appContext.getBean("CustomerBean");
obj.setId(1); //showing error
but I can't set the value to the particular CustomerBean class. To set the value it asking me to change the code like this.
CustomerBean obj = (CustomerBean) appContext.getBean("CustomerBean");
obj.setId(1);
I am having more than 1000 classes and each class having 5 to 10 variables. So please suggest me a better way to set a value to all the beans dynamically.
Thanks in advance.
All your beans may extend from parent classes with the properties to set or use reflection to assign the fields with values after you receive them from Spring:
import java.lang.reflect.Field;
public class Executor {
public static void main(String[] args) throws Exception {
TestClass testClass = new TestClass();
setValueToObject(testClass, "stringField", "someValue");
setValueToObject(testClass, "booleanField", true);
System.out.println(testClass.getStringField());
System.out.println(testClass.getBooleanField());
}
private static void setValueToObject(TestClass testClass, String filedName,
Object value) throws Exception {
Class objectClass = testClass.getClass();
Field field = objectClass.getDeclaredField(filedName);
field.setAccessible(true);
if (field.isAccessible()) {
field.set(testClass, value);
}
}
static class TestClass {
private String stringField;
private Boolean booleanField;
public String getStringField() {
return stringField;
}
public void setStringField(String stringField) {
this.stringField = stringField;
}
public Boolean getBooleanField() {
return booleanField;
}
public void setBooleanField(Boolean booleanField) {
this.booleanField = booleanField;
}
}
}
And notice that the beans will go for Singleton scope unless specified explicitly. You may change the bean scope as mentioned in this document.
It is against OOPs concept. You cannot call/access a method/property that is not defined in the parent (here Object) class. The Object class does not have "setId()" method.
Try this (Edited})
Just Create a Interface ValueSet { void setValueToVariables();} then Implement in ValueSet to All beans. Class CustomerBean implements ValueSet now you can implement setValueToVariables(). Change Object Class, that is ValueSet obj = (ValueSet) appContext.getBean("CustomerBean");
obj.setId(1);
I've an EJB as follows:
public class Bar() {
private String s;
public Bar() {
this.s = "bar";
}
#Inject public Bar(String s) {
this.s = s;
}
}
How can I inject that bean by using the arg-constructor into another Foo class?
Then, I define the Foo class as EJB, with the aim to perform the DI for it into another class (for instance, a WebServlet). How can I inject a Foo class instance by passing a String to properly set up Bar arg-constructor as inner-dependency?
Is there a better way to define Bar in order to achieve points above?
The annotated constructor injection tells CDI that whenever someone requests an instance of Bar to be injected, it should use the constructor marked with #Inject.
The CDI container then tries to get instances for all required constructor parameters and fails, because it can not deal with "String". It just doesn't know which String you mean.
You have to help the container resolving the dependency by using a Producer and a Qualifier to tell him what String you want. I just give you the simplest possible solution here:
public class Bar {
#Inject
public Bar(#Named("myString") String s) {
this.s = s;
}
}
And then another class (doesn't have to be an different class, but its much more readable):
public class MyStringProducer {
#Produces
#Named("myString")
public String getMyString() {
return ...; // whatever you want ... read JSON, parse properties, randomize ...
}
}
#Inject only works when you are injecting "managed" objects. String is not a managed object, thus this won;t work.
However, the following example should work (I have used spring here. Use the DI initializaton code according to the library you are using):
#Named
public class Foo {
#Inject
Bar bar;
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext("com.pkg1");
Foo foo = (Foo)ctx.getBean("foo");
System.out.println(foo.bar.getString());
}
}
#Named
public class Bar {
private String s;
public Bar() {
this.s = "bar";
}
#Inject
public Bar(Bar1 bar1) {
this.s = bar1.getS();
}
public String getString() {
return s;
}
}
#Named
class Bar1 {
private String s="bar1";
public String getS() {
return s;
}
}
It's not possible to use #Value on a static variable.
#Value("${some.value}")
static private int someValue;
static public void useValue() {
System.out.println(someValue);
}
When I do this, 0 is printed. So what is a good alternative to this?
Spring inject noting in static field (by default).
So you have two alternatives:
(the better one) make the field non static
(the ugly hack) add an none static setter which writes in the static field, and add the #Value annotation to the setter.
and then there is the trick with the MethodInvokingFactoryBean -- this example is for autowired fiels, but I guess you can adapt it for #Value too
Use this simple trick to achieve what you want (way better than having the value injected into non-static setters and writing so a static field - as suggested in the accepted answer):
#Service
public class ConfigUtil {
public static ConfigUtil INSTANCE;
#Value("${some.value})
private String value;
#PostConstruct
public void init() {
INSTANCE = this;
}
public String getValue() {
return value;
}
}
Use like:
ConfigUtil.INSTANCE.getValue();
To prevent ever repeating injections of the same value making a field non-static in a class that gets instantiated very often, I preferred to create a simple Singleton ConfigUtil as a workaround:
package de.agitos.app.util;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.beans.factory.annotation.Value;
/**
* Helper class to get injected configuration values from static methods
*
* #author Florian Sager
*
*/
#Configurable
public class ConfigUtil {
private static ConfigUtil instance = new ConfigUtil();
public static ConfigUtil getInstance() {
return instance;
}
private #Value("${my.value1}") Integer value1;
public Integer getValue1() {
return value1;
}
}
Inside the class I tried to inject the value first as a static Integer:
private static Integer value1 = ConfigUtil.getInstance().getValue1();
The following codes work for me,
public class MappingUtils {
private static String productTypeList;
#Value("${productType-list}")
public void setProductTypeList(String productTypeList) {
MappingUtils.getProductTypeList = productTypeList;
}
}
let's say you have a class name called config
so you initialize the static variable.
May be one can use the below approach for the same
class Config
{
private static int someValue;
private Config(#Value("${some.value}") int valueDuringInitialization)//private constructor
{
Config.someValue=valueDuringInitialization;
}
static public void useValue() {
System.out.println(someValue);
}
}