Reputation: 1534
Is there a way for java.lang.System to be used in dependency injection?
Currently I build my classes
public class MyClass
{
private final Dependency iDependency;
public MyClass(Dependency pDependency)
{
this.iDependency = pDependeny;
}
public static MyClass createInstance()
{
final Dependency tDependency = Dependency.createInstance();
final MyClass tInstance = new MyClass(tDependency);
return tInstance;
}
// ... class methods ...
}
and create it using:
MyClass tMyClass = MyClass.createInstance();
and for test I use:
@Test
public void testMethod()
{
// Setup
Dependency tTestDependency = new TestDependency();
MyClass tMyClass = new MyClass(tTestDependency);
// Test
tMyClass.method();
}
Now I have the problem that I have java.lang.System as dependency as I want to write a console logger. I have no problem setting System as a Datatyp for the dependency however Eclipse says no when I want to set System as parameter. I get the error "System cannot be resolved to a variable".
public class ConsoleLogger
{
private final System iSystem; // works
public MyClass(System pSystem) // works
{
this.iSystem = pSystem;
}
public static ConsoleLogger createInstance()
{
final ConsoleLogger tInstance = new ConsoleLogger(System); // Here I get an error: System cannot be resolved to a variable
return tInstance;
}
public void logInfo(String pMessage)
{
final String tPrintMsg = this.iSystem.currentTimeMillis() + " INFO - " + pMessage;
this.iSystem.out.println(tPrintMsg);
}
}
I could set System.err and System.out as dependencies with the datatype PrintStream but System.currentTimeMillies() would still not be covered.
Somebody an idea how to handle System as dependency in this scenario?
Upvotes: 1
Views: 161
Reputation: 718678
What you are doing doesn't make a lot of sense. The System
class is final
and has a private
constructor, so you cannot instantiate it. Besides, all of its methods and fields are static, so there is no point instantiating it and no point having an variable of that type.
Just to help you understand, when you refer to a static method or field via an reference to an instance, the reference is ignored. Thus, these two version of logInfo
do EXACTLY the same thing.
public void iLogInfo(String pMessage)
{
final String tPrintMsg = this.iSystem.currentTimeMillis() + " INFO - " + pMessage;
this.iSystem.out.println(tPrintMsg);
}
public void sLogInfo(String pMessage)
{
final String tPrintMsg = System.currentTimeMillis() + " INFO - " + pMessage;
System.out.println(tPrintMsg);
}
(This is one of those cases where the Java language allows you to write code that means something a bit different than it appears to. Style checkers and (IIRC) some IDEs will warn you if you refer to a static member via an instance reference. IMO it is a good idea to heed the warning.)
Upvotes: 1
Reputation: 20442
The System class contains several useful class fields and methods. It cannot be instantiated.
I think you would have to make an interface and use a delegate implementation. Even then, it won't quite be the same because you can't have static methods.
interface MySystem {
PrintStream getOut();
InputStream getIn();
....
}
class MySystemImpl {
PrintStream getOut() {
return System.out;
}
...
}
Upvotes: 3
Reputation: 5277
System.out, System.in, and System.err, as well as System.currentTimeMillis() are all static methods on System. I'd make out and err dependencies and then have a DateUtil bean that you can wire in with the method currentTimeMillis. You could do this with a SystemWrapper bean, but out and err seem pretty separate from date operations.
Upvotes: 0