eclipse-jdt / eclipse.jdt.core

Eclipse Public License 2.0
155 stars 122 forks source link

StringConcatFactory can not be resolved #1842

Closed laeubi closed 2 weeks ago

laeubi commented 7 months ago

Today I got a quite strange error in the IDE

The type java.lang.invoke.StringConcatFactory cannot be resolved. It is indirectly referenced from required .class files

but I never use that anywhere in my code.

The only "special" think seems be that my code is using java 1.8 JVM, I already cleaned the project but the project still persist.

laeubi commented 7 months ago

When I change the project settings to use Java 17 for example the problem vanishes, compiling with maven/tycho that also uses ecj works without a problem...

iloveeclipse commented 7 months ago

I saw this error today playing with one old 1.8 based plugin project containing e4 views that use old injection & annotation libs. Once switched to 17 & updating to jakarta namespace the error went away too.

laeubi commented 7 months ago

It might work with any Java 9+ as it is since 9 here:

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/invoke/StringConcatFactory.html

could it bee that if a dependency is using higher / more recent compile code it becomes an issue?

srikanth-sankaran commented 7 months ago

Today I got a quite strange error in the IDE

The type java.lang.invoke.StringConcatFactory cannot be resolved. It is indirectly referenced from required .class files

but I never use that anywhere in my code.

The only "special" think seems be that my code is using java 1.8 JVM, I already cleaned the project but the project still persist.

There is some class file that has been compiled at a level >=9 - if you use + to concatenate strings, the dependency to StringConcatFactory gets encoded into the class files for levels >=9

laeubi commented 7 months ago

There is some class file that has been compiled at a level >=9 - if you use + to concatenate strings, the dependency to StringConcatFactory gets encoded into the class files for levels >=9

How could that be if I have java 1.8 in project settings and clean the project?

iloveeclipse commented 7 months ago

How could that be if I have java 1.8 in project settings and clean the project?

One of the project dependencies is compiled with Java 9+?

laeubi commented 7 months ago

How could that be if I have java 1.8 in project settings and clean the project?

One of the project dependencies is compiled with Java 9+?

That's what I suspect but the error is really odd/not very helpful and does that mean that one can no longer build code in the IDE for java 1.8 target if one of its dependencies are Java 9+? then I think a specific error message should be emitted mention the offending dependency.

srikanth-sankaran commented 7 months ago

@jarthana, your take on @laeubi's observation here ??

szarnekow commented 7 months ago

one can no longer build code in the IDE for java 1.8 target

How would you run the code on the 1.8 JRE - the class file version would be to big.

Is the solution to compile against a JRE 9+ but use the --release flag?

laeubi commented 7 months ago

I can compile (with Tycho!) without a problem, just the IDE shows these strange "indirectly referenced from required .class files" ... An yes it uses the --release for this.

sengsational commented 5 months ago

I'm having this same issue. For years I had zero issues with Luna and finally upgraded. Now, I import a project from GitHub that I could import before, and I get this. A showstopper. I guess I'm going to give up on upgrading Eclipse.

chrisrueger commented 5 months ago

Similar issue here after I upgrade from 2023-12 to 2024-03 yesterday. Stuff like: The type org.apache.commons.logging.Log cannot be resolved. It is indirectly referenced from required type org.springframework.dao.support.DaoSupport suddenly appears.

image

Trying to go back to 2023-12 now, since my project is not building anymore. Building on the commandline (Gradle bndtools works fine though).

jarthana commented 5 months ago

Similar issue here after I upgrade from 2023-12 to 2024-03 yesterday. Stuff like: The type org.apache.commons.logging.Log cannot be resolved. It is indirectly referenced from required type org.springframework.dao.support.DaoSupport suddenly appears.

image

Trying to go back to 2023-12 now, since my project is not building anymore. Building on the commandline (Gradle bndtools works fine though).

Have you tried the suggestion from @szarnekow to use --release in the IDE? At the moment, I can't think of another solution to this.

chrisrueger commented 5 months ago

Have you tried the suggestion from @szarnekow to use --release in the IDE? At the moment, I can't think of another solution to this.

If you are referring to this checkbox, then yes, it was checked. I think it has always been checked in my case.

image
chrisrueger commented 5 months ago

I can confirm the errors go away after rolling back from 2024-03 to 2023-12.

chrisrueger commented 2 months ago

Any Update?

I just tested with upcoming Eclipse

Version: 2024-06 M2 (4.32.0 M2)
Build id: 20240502-0722

Update: And with latest I-Build:

Eclipse SDK

Version: 2024-06 (4.32)
Build id: I20240529-1800

The problem is still there.

image image image image

Any other workaround ideas? I am still on Eclipse 2023-12 where I do not have this problem. But I would like to upgrade :)

bogiva commented 2 months ago

I am having the same problem using vscode-java from 1.31.0 (May 30th, 2024).

Edit: turned out my case is not caused by jdt (alone) but rather a misconfiguration in vscode-java, i.e. it does not seem to be caused by jdt but I will nevertheless leave this info here just in case someone else ends up here.

It took me a while to find out how to configure and how to make it stable (survive restarts).

  1. In .vscode/settings.json specify:
    "java.import.gradle.java.home": "/my/jvm/path",
    "java.configuration.detectJdksAtStart": false,
    "java.configuration.runtimes": [
        {
            "name": "JavaSE-17",
            "path": "/my/jvm/path",
            "default": true
        }
    ],
  2. In "Java Projects" open "Configure Java Runtime" and in "JDK Runtime" dropdown box select the same JDK as configured in the settings.json.

Setting either of these two alone does not solve the problem. Setting JDK Runtime in step 2 solves the problem only for the current session, the setting is lost during restart of VSCode.

This probably deserves a ticket to vscode-java extension.

srikanth-sankaran commented 2 months ago

@jarthana Are you able to reconstruct one or more scenarios where the problem can be observed so we can study options available for us ?

iloveeclipse commented 2 months ago

Reading through the bug again it seems to me that the problem is the projects using -target 8 instead of --release 8 and the users of such projects run into troubles executing the code on Java 8 because projects compiled on Java 21 with -target 8 can freely use any Java 9+ API's.

So not sure if that is really compiler issue at all as the compiler just does what it was told by user.

laeubi commented 2 months ago

So not sure if that is really compiler issue at all as the compiler just does what it was told by user.

So the user told the compiler to use StringConcatFactory and then complain it can not be found? :-)

No one complained about the code producing any runtime problems, just the IDE shows strange errors... If its compiled with Java 21 it should be able to resolve StringConcatFactory with Java 21 as well?

iloveeclipse commented 2 months ago

No one complained about the code producing any runtime problems, just the IDE shows strange errors

I believe it would be very handy to have at least one simple reproducer everyone can look at. Any discussion without that is wasted time.

jarthana commented 2 months ago

No one complained about the code producing any runtime problems, just the IDE shows strange errors

I believe it would be very handy to have at least one simple reproducer everyone can look at. Any discussion without that is wasted time.

Indeed. The symptom is common and looking at Christoph's scenario, it appears this has nothing to do with StringConcatFactory, or we are dealing with two different issues. It will be good to have the bug extracted into a small workspace or project.

laeubi commented 2 months ago

It seems you already have a reproducer:

I saw this error today playing with one old 1.8 based plugin project containing e4 views that use old injection & annotation libs. Once switched to 17 & updating to jakarta namespace the error went away too.

So maybe this can be shared?

stephan-herrmann commented 2 months ago

It's actually quite easy to reproduce given the discussion above:

issue1842.zip

This shows a situation where this exact error message is actually justified.

There may be situations where we can avoid touching the sore spot (see #543), but it cannot be eliminated completely.

stephan-herrmann commented 2 months ago

The type org.apache.commons.logging.Log cannot be resolved. It is indirectly referenced from required type org.springframework.dao.support.DaoSupport suddenly appears.

Nice, finally we see effect of #327. @chrisrueger , does this help to trace the causality?

chrisrueger commented 2 months ago

@stephan-herrmann thanks for the .zip reproducer:

When I import this in my (old) Eclipse 2023-12 (!) (this is the Eclipse still working) then I see this:

This appears right after import the "Existing projects into Workspace". My Eclipse had JDK21 as default JRE.

Description Resource    Path    Location    Type
The project was not built since its build path is incomplete. Cannot find the class file for java.lang.invoke.StringConcatFactory. Fix the build path then try building this project    Client_1_8      Unknown Java Problem
The type java.lang.invoke.StringConcatFactory cannot be resolved. It is indirectly referenced from required type p17.LibClass   Client.java /Client_1_8/src/p_1_8   line 7  Java Problem
image

When I change default JRE to JDK17 the error changes to:

Description Resource    Path    Location    Type
The method m(StringConcatFactory) is ambiguous for the type LibClass    Client.java /Client_1_8/src/p_1_8   line 7  Java Problem
image

Now I try the same with eclipse-SDK-I20240529-1800:

Default JRE JDK21:

image

Default JRE JDK17:

image

I notice that this is different than on Eclipse 2023-12, because I do not see the errror "The type java.lang.invoke.StringConcatFactory cannot be resolved. It is indirectly referenced from required type "

BUT:

When I then manually change the Execution Environment to JDK 1.8.

image image

then the 2 errors are back:

Description Resource    Path    Location    Type
The project was not built since its build path is incomplete. Cannot find the class file for java.lang.invoke.StringConcatFactory. Fix the build path then try building this project    Client_1_8      Unknown Java Problem
The type java.lang.invoke.StringConcatFactory cannot be resolved. It is indirectly referenced from required type p17.LibClass   Client.java /Client_1_8/src/p_1_8   line 7  Java Problem

Both happens regardless if Eclipse Preferences Default JRE is still on JDK 17 , JDK 21, JDK 1.8).

  • can you see why DaoSupport needs Log?
  • can you see why your application needs DaoSupport?

We have a abstract class AbstractHibernateDAOImpl<T extends PersistentObject> extends HibernateDaoSupport import org.springframework.orm.hibernate5.support.HibernateDaoSupport;

and HibernateDaoSupport looks like this public abstract class org.springframework.orm.hibernate5.support.HibernateDaoSupport extends org.springframework.dao.support.DaoSupport

and org.springframework.dao.support.DaoSupport imports import org.apache.commons.logging.Log see https://github.com/spring-projects/spring-framework/blob/main/spring-tx/src/main/java/org/springframework/dao/support/DaoSupport.java#L19

I don't know how to answer the "why" other than: "because that's what our application does since ten years :)" It works in Eclipse 2023-12. Starting with Eclipse 2024-03 we see the error and cannot use the newer Eclipses anymore.

stephan-herrmann commented 2 months ago
  • can you see why DaoSupport needs Log?
  • can you see why your application needs DaoSupport?

We have a abstract class AbstractHibernateDAOImpl<T extends PersistentObject> extends HibernateDaoSupport import org.springframework.orm.hibernate5.support.HibernateDaoSupport;

and HibernateDaoSupport looks like this public abstract class org.springframework.orm.hibernate5.support.HibernateDaoSupport extends org.springframework.dao.support.DaoSupport

and org.springframework.dao.support.DaoSupport imports import org.apache.commons.logging.Log see https://github.com/spring-projects/spring-framework/blob/main/spring-tx/src/main/java/org/springframework/dao/support/DaoSupport.java#L19

Thanks, so looking for the missing class is not completely unfounded. The remaining, interesting question is: is type Log necessary for analysing your own code? This typically happens, when the type appears in some member signature which needs to be resolved in order to determine legality of your code.

The fact that you have the dependency (regarding Log) directly in a superclass (DaoSupport) of your own class (AbstractHibernateDAOImpl) makes it hard not to touch that dependency.

Seeing this field:

    /** Logger available to subclasses. */
    protected final Log logger = LogFactory.getLog(getClass());

actually indicates that the author assumed that subclasses have type Log in their dependencies, too! When subclassing DaoSupport type Log is also part of your own API.

chrisrueger commented 2 months ago

Found a solution I am using bndtools / OSGi. In the bundle which had the Eclipse error in the Problems view I had to add the dependency to the -buildpath in bnd.bnd

BundleA:

-buildpath:
org.apache.commons.logging

Then commons-logging-1.2.jar appeared on the Bnd Bundle Path and the error was gone:

image

Now I went back to the old Eclipse 2023-12 and checked how the Bnd bundle path looked before when org.apache.commons.logging was not explicitly added to the -buildpath in bnd.bnd:

Bnd bundle path was indeed not showing the commons-logging-1.2.jar but the error does not appear.

My personal conclusion:

It seems newer Eclipse >= 2024-03 is "stricter" and you need to add bundles to your -buildpath in bnd.bnd which maybe required indirectly e.g. by classes you are inheriting from (like protected members of 3rd pary classes which you are subclassing in your code, although your code does not use the inherited member directly). This was not needed before in Eclipse <= 2023-12

Mentioning @pkriens of bndtools to make him aware. Not sure if there is anything bndtools needs to do based on this observation.

Update: I just wanted to highlight a subtle difference in error messages which I observed in this discussion:

The discussion starts with the error:

The type java.lang.invoke.StringConcatFactory cannot be resolved. It is indirectly referenced from required .class files

vs. in my case I got:

The type org.apache.commons.logging.Log cannot be resolved. It is indirectly referenced from required type...

Notice the .class vs. type at the end of the messages. I did not notice this in the beginning. Sorry if I diluted this discussion. Maybe my problem is a different one than the original posted.

stephan-herrmann commented 2 months ago

It seems newer Eclipse >= 2024-03 is "stricter" ...

lots of things in a compiler are "demand-driven", such that small implementation changes can cause differences in which class files are needed during analysis. I don't think any specification exists, which defines a boundary between classes visible to the compiler and classes that it must not touch (although at runtime they need to be present).

A decent module system might actually report some of these situations as API-leaks: accessibility of members with inaccesible type.

In the end it's always a matter of "best-effort" trying to cope with missing classes based on some judgement that their absence will not affect the compilation outcome.

Update: I just wanted to highlight a subtle difference in error messages which I observed in this discussion:

The discussion starts with the error:

The type java.lang.invoke.StringConcatFactory cannot be resolved. It is indirectly referenced from required .class files

vs. in my case I got:

The type org.apache.commons.logging.Log cannot be resolved. It is indirectly referenced from required type...

Notice the .class vs. type at the end of the messages. I did not notice this in the beginning. Sorry if I diluted this discussion. Maybe my problem is a different one than the original posted.

The variant with .class is the old message. Since #327 we try to report where the failing lookup was triggered. Still seeing the old message only means that the addition from #327 did not provide any additional information.

So at face value both are reporting the same problem, but yes, the more general "from required .class files" indicates that perhaps the path to the missing type was more obscure.

chrisrueger commented 2 months ago

lots of things in a compiler are "demand-driven", such that small implementation changes can cause differences in which class files are needed during analysis. I don't think any specification exists, which defines a boundary between classes visible to the compiler and classes that it must not touch (although at runtime they need to be present).

A decent module system might actually report some of these situations as API-leaks: accessibility of members with inaccesible type.

In the end it's always a matter of "best-effort" trying to cope with missing classes based on some judgement that their absence will not affect the compilation outcome.

Thanks for the explanation. It wasn't my intent to negatively criticize this. I was just surprised. and often when something stops working as before, the initial reflex is to think this is a bug :)

But now that I know, I can react and solve our problem.

One question out of curiosity: How (or why) was it decided that this should be an error vs be a warning?

stephan-herrmann commented 2 months ago

One question out of curiosity: How (or why) was it decided that this should be an error vs be a warning?

I cannot say about the original decision, which happened before Eclipse became open source :)

What I can say is that this problem is classified as a build path problem. And generally all build path errors should be resolved before all other problems. Build path problems can be the root of various errors, so reporting with lesser severity would make people try to solve secondary problems before they even see the report of the (assumed) root cause.

chrisrueger commented 2 months ago

OK thanks. Just want to say: My problem is solved. Not sure if this is the case for the initial report by @laeubi

laeubi commented 2 months ago

Not sure if this is the case for the initial report by @laeubi

I think my problem is actually different, as far as I understood the discussion here your code "suddenly" required (indirectly) a user type, this always has been the case and as far as I know bnd tools even has a Quickfix for that (PDE should now as well for Automatic Manifest projects).

So even if the error message is similar the cause is different here as JDT complains about something from java.lang that is never used in the code anywhere (just indirectly due to compiler optimization) this should simply always be accessible and seems not very helpful to the user.

I see some options to really resolve this:

  1. Ignore any non resolvable Type of java.lang and hope for the best that another error show up or it actually is not an issue at all
  2. Have a polyfill type for StringConcatFactory if it cannot be found
  3. Instead complain that a dependency (I can only guess its the case?!) requires a higher Java version (currently only a warning in PDE)

Also it should be investigated if something in the compiler is using StringConcatFactory even though the source / target / .... is < 9 even though strictly it is allowed it seems not very useful and waiting for bad things to happen.

stephan-herrmann commented 2 months ago

So even if the error message is similar the cause is different here as JDT complains about something from java.lang that is never used in the code anywhere (just indirectly due to compiler optimization)

why do you say optimization? The main reason for loading referenced class files is for correctness of the compilation result.

1. Ignore any non resolvable Type of `java.lang` and hope for the best that another error show up or it actually is not an issue at all

ignoring an error and hoping for something doesn't sound like a strategy suitable for a compiler, if you ask me.

2. Have a polyfill type for `StringConcatFactory` if it cannot be found

from a compiler p.o.v. I don't see reason why this particular class should get special treatment.

As we know that this error message can be caused by a wide range of possible situations, I'd love to analyse your specific problem using a minimal reproducer.

Until we have a reproducer I'll focus on #543 instead.

laeubi commented 2 months ago

why do you say optimization?

Oracle/Java/JDK says that

Methods to facilitate the creation of String concatenation methods, that can be used to efficiently concatenate a known number of arguments of known types

So obviously there is (a less efficient) alternative or something else that was used before Java 9+

from a compiler p.o.v. I don't see reason why this particular class should get special treatment.

Again the javadoc gives some hint:

These methods are typically used as bootstrap methods for invokedynamic call sites, to support the string concatenation feature of the Java Programming Language.

So I (as a user) can't influence what the compiler emits here as I don't use this type anywhere in my code, it is more like a special byte-code instruction / built in, so I would expect it to only be used when the compiler is sure it can be used (Java >= 9) in contrast when I reference a Type in my sourceode where the compiler must use that.

That's why I think special treatment would be justified here as it is more a "language feature (Java doc says See The Java™ Language Specification: 5.1.11 String Conversion, 15.18.1 String Concatenation Operator +) than a regular classpath type.

stephan-herrmann commented 2 months ago

Thanks, @laeubi now I see where you are coming from. You seem to say that the compiler chose an optimization strategy in a configuration where the class required for that strategy is not available.

That's not, however, how I read the error. The type java.lang.invoke.StringConcatFactory cannot be resolved. It is indirectly referenced from required .class files

Saying "indirectly referenced from required .class files" seems to indicate the following two-step scenario:

It's this "something" we need to know in order to investigate, in order to see whether or not StringConcatFactory is actually needed for compiling Y.

laeubi commented 2 months ago

Thanks for the additional explanation @stephan-herrmann

in a separate compiler invocation another class Y was compiled, where the source code mentions X in one way or other. in this second invocation class StringConcatFactory is no-where to be found something still causes the compiler to analyse X.class in a way that requires lookup of StringConcatFactory

As it is a very special java class, one might think about that if the compiler find java.lang.StringConcatFactory but can't look it up I think there are two ways:

  1. As we "know" how StringConcatFactory looks like, one could simply use some polyfill type that is simulating the type is there, this is a very common practice in backward compatibility scenarios.
  2. At least one could give a more specific message e.g. that actually a dependency requires a higher java version (that at best would mention X.class and maybe even from wehre it was loaded e.g. X.class (previously loaded from X-lib.jar) requires Java 9+ and Y indirectly references it but currently is compiled for Java 1.8
stephan-herrmann commented 2 months ago

As it is a very special java class, one might think about

Should we focus on addressing the special symptom regarding StringConcatFactory, or on finding the root cause that also affects many other situations?

I very much prefer solving root causes than introducing kludges for specific situations (without having understood their root cause).

Thinking of better diagnostics is of course a useful approach, that's what we did in #327 already, and I'm surprised that your issue is not helped, i.e., in your case we are unable to provide the additional information.

So here's a proposal: we could introduce a "hidden" flag via a system property that will let the compiler print more debug information (mostly: stacktrace) to console when the problem occurs. Will you be able to reproduce the problem with a compiler from a PR or I-Build and report back any stacktraces that will be printed with that flag enabled?

Otherwise I would wait what happens first:

laeubi commented 2 months ago

Should we focus on addressing the special symptom regarding StringConcatFactory, or on finding the root cause that also affects many other situations?

The situation is that one see the error when the project uses Java 1.8 and goes away once one uses a higher Java version, so I'm not sure what else should be the root cause than that Java 1.8 does not has StringConcatFactory ... sadly I currently have no reproducer as back then I just raised the java version...

stephan-herrmann commented 2 months ago

I'm not sure what else should be the root cause than that Java 1.8 does not has StringConcatFactory

Let's call this the surface cause.

What we need is understanding why the compiler considers StringConcatFactory necessary for compilation in that particular setup:

stephan-herrmann commented 1 month ago

@laeubi may we close this, since (a) #2543 reduced the effect of missing types and (b) we don't seem to have a reproducer?

stephan-herrmann commented 2 weeks ago

I don't see anything we can reasonably do here. Closing.