0

I have a JakartaEE java webapp (say project A) and a java library project/jar (say project B). Project B is imported in Project A as a dependency via maven.

I have a singleton instance of a class (say obj1) injected into a class (say Class2) in Project A via Guice. Project B does not import nor know about the class of obj1 (i.e. trying to add an instance of obj1's class in Project B leads to a compilation error).

I have defined the following functional interface in Class2 of Project A:

    public final Function<String,InputStream> func = str -> {
        return obj1.get(str);
    };

I pass the variable func to a method in Project B and then call apply on it there.

I am confused to as to how calling apply on func in Project B works given the fact that obj1's class is technically not visible in Project B.

I guess I'm trying to understand how this works internally/after compilation. Thanks.

Kevin
  • 635
  • 3
  • 9
  • 18
  • You say that Project B does not know about Project A, but how are you running this? You put both projects on the class path, right? If so, then they would know about each other. – Sweeper Aug 27 '21 at 09:04
  • 2
    You have not “defined a functional interface”. You have *implemented* it, via a lambda expression. This, however, is entirely irrelevant. When you receive a `Function` object, you can invoke `apply` on it, as all types, `Function`, `String`, and `InputStream` are part of the always available standard API. It doesn’t matter how it has been implemented. That’s the whole point of interfaces, or APIs in general. You invoke a method and it doesn’t matter, how the method has been implemented. – Holger Aug 27 '21 at 09:06
  • @Sweeper yes they are in the classpath. However `obj1` is an instance of a class from a third project C which is imported in project A but not in project B. – Kevin Aug 27 '21 at 11:16
  • @Holger oops I guess I didn't use the right terminology. `obj1` however is not a part of the standard Java API but rather is a custom class instance that is part of a third different project C which is imported in A but not in B. Yet in B the code works and that is where my confusion lies. – Kevin Aug 27 '21 at 11:18
  • 2
    There is no `obj1` in `Function`. You are still confusing the interface with the implementation. The whole point of abstraction and encapsulation is that you don’t have to care, how something has been implemented. When you execute `Collections.emptyList().size()`, you are calling the `size()` method on an implementation specific non-public class. Which is no problem as you are calling it using the `List` interface. When you call `"foo".charAt(1)`, you are executing a method which will read the internal array held in a `private` variable. That’s how it works, everywhere. – Holger Aug 27 '21 at 11:36
  • Hi, I'm not sure, but it sounds like closure: https://stackoverflow.com/questions/3805474/what-is-a-closure-does-java-have-closures – Grzegorz Aug 27 '21 at 19:21
  • 1
    Regarding the relevance of `import` statements, you may also read [Do Java Lambda Expressions Utilize “Hidden” or Local Package Imports?](https://stackoverflow.com/q/28180695/2711488) – Holger Aug 28 '21 at 08:49

1 Answers1

0

Lets go step by step..

Let assume your method in Project B is called projectMethod and it is expected input parameter of type Function<String,InputStream>

public {retrunType} projectMethod(Function<String,InputStream> func) {
    // implementation
}

Since Function (java.util.function.Function) is an interface, when we call projectMethod method, we must provide and implementation for Function interface. Therefore projectMethod know any implementation of Function interface must override abstract method apply.

In this scenario the apply methods signature is public InputStream apply(String s). Therefore projectMethod knows if we called apply method, it will return a output of type InputStream.

In your example you have provided an implementation for Function<String,InputStream> interface.

Most naïve implementation for Function<String,InputStream> interface is as follows,

public class FunctionImpl implements Function<String, InputStream> {
    @Override
    public InputStream apply(String s) {
        return YourSingletonClass.get(s);
    }
}

Then you can pass that to method as follows,

projectMethod(new FunctionImpl());

You can improve your implementation of Function<String,InputStream> like you have mentioned. Your implementation can do some improvement like this,

public final Function<String,InputStream> func = YourSingletonClass::get

Then you can call method like this,

projectMethod(func);

If we look carefully, we can omit public final Function<String,InputStream> this declaration and directly call the method,

projectMethod(YourSingletonClass::get); 
ray
  • 1,512
  • 4
  • 11