Xeno Lupus
Xeno Lupus

Reputation: 1534

Handle System as a dependency

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

Answers (3)

Stephen C
Stephen C

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

Tim Bender
Tim Bender

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

Zeki
Zeki

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

Related Questions