Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #38719 > unrolled thread

How to make my library independent using DI

Started bymike <mikaelpetterson@hotmail.com>
First post2019-01-29 10:11 -0800
Last post2019-02-04 16:33 +0100
Articles 6 — 4 participants

Back to article view | Back to comp.lang.java.programmer


Contents

  How to make my library independent using DI mike <mikaelpetterson@hotmail.com> - 2019-01-29 10:11 -0800
    Re: How to make my library independent using DI Martin Gregorie <martin@mydomain.invalid> - 2019-01-29 19:29 +0000
    Re: How to make my library independent using DI Andreas Leitgeb <avl@logic.at> - 2019-01-30 10:11 +0000
      Re: How to make my library independent using DI mike <mikaelpetterson@hotmail.com> - 2019-01-30 06:13 -0800
        Re: How to make my library independent using DI Andreas Leitgeb <avl@logic.at> - 2019-02-01 14:13 +0000
    Re: How to make my library independent using DI Daniele Futtorovic <da.futt.news@laposte-dot-net.invalid> - 2019-02-04 16:33 +0100

#38719 — How to make my library independent using DI

Frommike <mikaelpetterson@hotmail.com>
Date2019-01-29 10:11 -0800
SubjectHow to make my library independent using DI
Message-ID<c9bc00ee-744c-49e2-b026-08a68841cf48@googlegroups.com>
Hi,

I am creating a library that can be used with different java applications.
Sometimes I need data from different applications but I want to avoid a direct dependency to these applications.

In my library I have the following classes:

package scrap;


public interface MyDataClass {
    String productNumber();
    String version();
    String time();


}

and 

public class MyDataClassImpl implements MyDataClass{
    
    private ExternalDataService externalDataService;
    
    public MyDataClassImpl(ExternalDataService externalDataService){
        this.externalDataService = externalDataService;
    }

    @Override
    public String productNumber() {
      //Here we have a dependency to an external library call it x
       return externalDataService.productNumber();
    }

    @Override
    public String version() {
        //Here we have a dependency to an external library call it x
       return externalDataService.version();
    }

    @Override
    public String time() {        
      return calcTime();
    }
    
    
    private String calcTime () {
        return "";
        
    }
}

as well as:

package scrap;


public interface ExternalDataService {
    
    public String productNumber();
    
    public String version();

}


Then in the application using this lib I have:

package other;

import scrap.ExternalDataService;

public class AHelper implements ExternalDataService{

    @Override
    public String productNumber() {
        return methodA();
    }

    @Override
    public String version() {
        return methodB();
    }
    
    
    public String methodA() {
        return "";
    }
    
    String methodB() {
        return "";
    }
}

I have two questions:

1. How can I inject AHelper into MyDataClassImpl without creating a "hard dependency" without using a DI container?
2. If I used a container like Guice how would that look like? 

All hints welcome.

br,

Mike

[toc] | [next] | [standalone]


#38720

FromMartin Gregorie <martin@mydomain.invalid>
Date2019-01-29 19:29 +0000
Message-ID<q2q9iq$41a$2@news.albasani.net>
In reply to#38719
On Tue, 29 Jan 2019 10:11:52 -0800, mike wrote:

> Hi,
> 
> I am creating a library that can be used with different java
> applications.

I've had one for years - just like a similar C library that I started 
even earlier. I think its best to just let these things grow:

- I didn't like the standard C getopt() function, so wrote my own, which 
can also parse out non-option items on the command line and, knowing I'd 
use this a lot, it went straight into my support library. Somewhat later 
it got reimplemented in Java as my ArgParser class: there is no standard 
equivalent and something like it is essential if you tend to write non-
graphical Java programs. 

- I've done the same for tracing and debugging packages, and added other 
stuff as and when I needed to write it: circular buffers that hold the 
last 'n' log messages, a CSV support package, also my own design of 
regression testing support code ....

The trick is simply to recognise that a piece of code may be useful in 
other places too, write it from the outset to be free from application-
specific dependencies, add a regression test harness for it, and lob it 
into your support package rather than blindly building it into the 
application you're working on.
 

-- 
Martin    | martin at
Gregorie  | gregorie dot org

[toc] | [prev] | [next] | [standalone]


#38721

FromAndreas Leitgeb <avl@logic.at>
Date2019-01-30 10:11 +0000
Message-ID<slrnq52u2s.k8o.avl@logic.at>
In reply to#38719
mike <mikaelpetterson@hotmail.com> wrote:
> In my library I have the following classes:
> public interface MyDataClass {
>    [...]
> }
> public class MyDataClassImpl implements MyDataClass{
>     private ExternalDataService externalDataService;
>     public MyDataClassImpl(ExternalDataService externalDataService){
>         this.externalDataService = externalDataService;
>     }

I'd consider this design already fine w.r.t. independence of
lib from app.

>     public String productNumber() {
>       //Here we have a dependency to an external library call it x
>        return externalDataService.productNumber();
>     }

You might want to wrap this with a null check for the field, such that
if a user of the lib doesn't provide an implementation (but instead null),
they could still get around.

If the lib doesn't make sense without at least some implementation of
ExternalDataService, then you can leave it as is here, and instead let
the constructor throw some exception for a null argument. There might
even be @NotNull annotations, but I don't know how reliable they are,
or whether they are already available in the versions of Java you use.

> public interface ExternalDataService {
>     public String productNumber();
>     public String version();
> }
>
> Then in the application using this lib I have:
> public class AHelper implements ExternalDataService{
>    [...]
> }
> I have two questions:
>
> 1. How can I inject AHelper into MyDataClassImpl without creating
> a "hard dependency" without using a DI container?

Not sure what you mean by inject, but according to your code snippet,
there is no "hard dependency" to AHelper in your lib.

Unless you strictly disallow "null", there isn't even a necessity
that a user even implements ExternalDataService at all.

> 2. If I used a container like Guice how would that look like? 

I don't know Guice, so can't tell.

[toc] | [prev] | [next] | [standalone]


#38722

Frommike <mikaelpetterson@hotmail.com>
Date2019-01-30 06:13 -0800
Message-ID<e09b44b3-55fd-4dc9-a16c-156e1bd4fff8@googlegroups.com>
In reply to#38721
Hi Andreas,

Thanks for your comments. I really appreciate them.

> Not sure what you mean by inject, but according to your code snippet,
> there is no "hard dependency" to AHelper in your lib.

I will definitely check for null.

I think I need to do a litte bit more explanation.

I need to create an instance of AHelper, in the application using the library,and inject it into my lib. Otherwise I will not be able to access the data from
 version() and productNumber().

I mean shall I call:

MyDataClassImpl( new AHelper()) from the application? And at what point in time should this be done.
And if the MyDataClassImpl needs more external data, let's say from BHelper() also, do add the following in my app:

MyDataClassImpl(new AHelper(),new BHelper()) ?


Thanks for helping out!!

//mikael


[toc] | [prev] | [next] | [standalone]


#38723

FromAndreas Leitgeb <avl@logic.at>
Date2019-02-01 14:13 +0000
Message-ID<slrnq58kvi.k8o.avl@logic.at>
In reply to#38722
mike <mikaelpetterson@hotmail.com> wrote:
> I need to create an instance of AHelper, in the application using the library,
> and inject it into my lib. Otherwise I will not be able to access the data from
> version() and productNumber().
> I mean shall I call:
> MyDataClassImpl( new AHelper()) from the application?

That's surely the most straightforward thing to do.

There might be other options (even as ugly as involving
static fields - don't do that, unless the application
really only needs a single instance for the whole VM)

> And at what point in time should this be done.

Apparently exactly when you need the instance of MyDataClassImpl

if more classes of the library need a reference to an 

> And if the MyDataClassImpl needs more external data, let's say
> from BHelper() also, do add the following in my app:
> MyDataClassImpl(new AHelper(),new BHelper()) ?

If the new data is *necessary* you just add new methods to the
interface in the lib, and it will require  other applications
to upgrade along with the lib (or stick to older versions of
the lib)

If you're on Java8 or newer, and if it makes sense, you might
add default-implementations to the interface for the new methods,
so the lib will remain compatible with old apps, (but not with
Java7 or older, then)

Different helpers (imho) only make sense, if they cover different
parts of the library, and aren't always necessary at the same time.

[toc] | [prev] | [next] | [standalone]


#38724

FromDaniele Futtorovic <da.futt.news@laposte-dot-net.invalid>
Date2019-02-04 16:33 +0100
Message-ID<q39m0g$l2$1@dont-email.me>
In reply to#38719
On 2019-01-29 19:11, mike wrote:
> Hi,
> 
> I am creating a library that can be used with different java applications.
> Sometimes I need data from different applications but I want to avoid a direct dependency to these applications.
> 
> In my library I have the following classes:
> 
> package scrap;
> 
> 
> public interface MyDataClass {
>     String productNumber();
>     String version();
>     String time();
> 
> 
> }
> 
> and 
> 
> public class MyDataClassImpl implements MyDataClass{
>     
>     private ExternalDataService externalDataService;
>     
>     public MyDataClassImpl(ExternalDataService externalDataService){
>         this.externalDataService = externalDataService;
>     }
> 
>     @Override
>     public String productNumber() {
>       //Here we have a dependency to an external library call it x
>        return externalDataService.productNumber();
>     }
> 
>     @Override
>     public String version() {
>         //Here we have a dependency to an external library call it x
>        return externalDataService.version();
>     }
> 
>     @Override
>     public String time() {        
>       return calcTime();
>     }
>     
>     
>     private String calcTime () {
>         return "";
>         
>     }
> }
> 
> as well as:
> 
> package scrap;
> 
> 
> public interface ExternalDataService {
>     
>     public String productNumber();
>     
>     public String version();
> 
> }
> 
> 
> Then in the application using this lib I have:
> 
> package other;
> 
> import scrap.ExternalDataService;
> 
> public class AHelper implements ExternalDataService{
> 
>     @Override
>     public String productNumber() {
>         return methodA();
>     }
> 
>     @Override
>     public String version() {
>         return methodB();
>     }
>     
>     
>     public String methodA() {
>         return "";
>     }
>     
>     String methodB() {
>         return "";
>     }
> }
> 
> I have two questions:
> 
> 1. How can I inject AHelper into MyDataClassImpl without creating a "hard dependency" without using a DI container?
> 2. If I used a container like Guice how would that look like? 
> 
> All hints welcome.
> 
> br,
> 
> Mike
> 

You don't need an "ExternalDataService". It doesn't matter whether the
data is internal or external. You just need a data class and a data
provider class.

public interface Data {
  String productNumber();
  String version();
  String time();
}

public interface DataProvider
  extends Supplier<Data>
{}

In order to get hold of DataProvider instances, I would suggest looking
into the java.util.ServiceLoader mechanism (see Javadoc
<https://docs.oracle.com/javase/10/docs/api/java/util/ServiceLoader.html>).

In your own API then, you simply try to load a DataProvider. If you find
one, get your data from there. If not, simply throw up.

-- 
DF.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.java.programmer


csiph-web