Re: jdeps - option to to analyze package-private API

2022-12-13 Thread Matej Turcel

On 12.12.2022 16:26, Alan Bateman wrote:
The scenario seems a bit unusual in that API elements with package 
access aren't usually considered to be part of the API.


Yes, they shouldn't be. But our code is not perfect and we have many 
cases where package-private elements de-facto are a part of the API.


I realize Gradle may define "module" to mean something else but for 
the Java platform, a module is a set of packages.


Gradle currently does not support specifying which packages are a part 
of the API, although according to the docs [1] this should be possible 
in a future release. However, doing so would require a massive effort on 
our side since we need to figure out which packages should be a part of 
the API and our codebase is quite large. But if we were to do this (and 
we may, as an intermediate step in our transition to jigsaw), the 
functionality I propose would be very helpful in doing so.


I may note that we only consider as API those packages, which are 
actually used from another module -- not everything package-private is 
automatically in the API.


[1] 
https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_recognizing_dependencies 



I haven't seen any opinions from others but my initial reaction is 
that it wouldn't be a good idea to change --api-only to consider API 
elements with package access to be part of the API. If jdeps were 
changed then it would need a new option.
Of course, that was my idea as well. FYI, I have already implemented 
this change, and I would like to make these changes directly in OpenJDK 
as well to avoid maintenance burden. For example, JDK-8294969 will break 
my changes, so I will have to rewrite them when we switch to newer JDK.

jdeps - option to to analyze package-private API

2022-12-03 Thread Matej Turcel

Hello,

I would like to propose a new option for jdeps, similar to --api-only,
which would analyze not only private and protected API (like --api-only
does), but also package-private API. In more detail, this option would
report all dependencies which occur in all types (not only public ones),
namely in the type's:
- non-private members (= public, protected, or package-private),
- signatures of non-private constructors and methods,
- one of the above inside an arbitrarily deeply nested inner type,
  such that all its enclosing types are non-private.

A little bit about the motivation for this additional functionality.
We use Gradle to build our product, and have several hundred modules
with a few thousands mutual dependencies between them. With each change
in the source code, developers must manually update the Gradle module
dependencies and ensure they have the correct type, e.g. `api` or
`implementation` (there are more types but they are not relevant here).
With tens of thousands of classes, this gets out of hand quickly, and
as a result, the dependencies declared in our build.gradle files often
do not match the actual dependencies of the underlying source code.
Naturally, we would like to automatically analyze the code and obtain
correct dependency types, and since we use several JDK languages, we want
to analyze bytecode using jdeps, instead of analyzing source code as that
would require having a separate front-end for each language we use.

So far, jdeps with the --api-only flag seems like the perfect tool, except
there is a little problem -- we have packages (dozens of them) which
exist in multiple modules. For example, package `com.foo` exists in
three separate modules (meaning each of these modules has a class in that
package). That means package-private "stuff" (members + constructor/method
signatures) is a part of module's API. So to infer correct types of gradle
module dependencies using jdeps, we need jdeps to consider package-private
stuff a part of the API.

On an unrelated note, I believe bounds of type parameters should be
a part of type's API:

    public class C {
    T x;
    }

But according to jdeps they are not:

    > jdeps --verbose C.class
    C.class -> java.base
   C   -> java.lang.Boolean    java.base
   C   -> java.lang.Object java.base

    > jdeps --verbose --api-only C.class
    C.class -> java.base
   C   -> java.lang.Object java.base

Is this behavior intended?