Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

StringConcatFactory can not be resolved #1842

Closed
laeubi opened this issue Jan 11, 2024 · 43 comments
Closed

StringConcatFactory can not be resolved #1842

laeubi opened this issue Jan 11, 2024 · 43 comments
Assignees
Labels
bug Something isn't working

Comments

@laeubi
Copy link
Contributor

laeubi commented Jan 11, 2024

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
Copy link
Contributor Author

laeubi commented Jan 11, 2024

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
Copy link
Member

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
Copy link
Contributor Author

laeubi commented Jan 11, 2024

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
Copy link
Contributor

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
Copy link
Contributor Author

laeubi commented Jan 12, 2024

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
Copy link
Member

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
Copy link
Contributor Author

laeubi commented Jan 12, 2024

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
Copy link
Contributor

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

@szarnekow
Copy link
Contributor

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
Copy link
Contributor Author

laeubi commented Jan 12, 2024

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
Copy link

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
Copy link

chrisrueger commented Mar 18, 2024

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
Copy link
Member

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
Copy link

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
Copy link

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

@chrisrueger
Copy link

chrisrueger commented May 30, 2024

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
Copy link

bogiva commented Jun 4, 2024

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
        }
    ],
  1. 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.

@iloveeclipse iloveeclipse added bug Something isn't working compiler Eclipse Java Compiler (ecj) related issues labels Jun 6, 2024
@srikanth-sankaran
Copy link
Contributor

@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 iloveeclipse removed the compiler Eclipse Java Compiler (ecj) related issues label Jun 6, 2024
@iloveeclipse
Copy link
Member

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
Copy link
Contributor Author

laeubi commented Jun 6, 2024

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
Copy link
Member

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
Copy link
Member

jarthana commented Jun 6, 2024

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
Copy link
Contributor Author

laeubi commented Jun 6, 2024

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
Copy link
Contributor

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
Copy link
Contributor

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?

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

@chrisrueger
Copy link

chrisrueger commented Jun 6, 2024

@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
Copy link
Contributor

  • 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
Copy link

chrisrueger commented Jun 6, 2024

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
Copy link
Contributor

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
Copy link

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
Copy link
Contributor

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
Copy link

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

@laeubi
Copy link
Contributor Author

laeubi commented Jun 7, 2024

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
Copy link
Contributor

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
Copy link
Contributor Author

laeubi commented Jun 8, 2024

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
Copy link
Contributor

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:

  • during some compiler invocation a classfile (say: X.class) was generated that legitimately refers to class StringConcatFactory
    • this could be implicitly as an optimization of string concatenation or explicitly, that we don't know
  • 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

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.

  • if needed, then the compiler is right to complain, the configuration for compiling Y does not allow you to use X in the way you do
  • if not needed, then we need to figure out, which code path in the compiler wrongly decides to look up StringConcatFactory

@laeubi
Copy link
Contributor Author

laeubi commented Jun 8, 2024

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
Copy link
Contributor

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
Copy link
Contributor Author

laeubi commented Jun 9, 2024

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
Copy link
Contributor

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:

  • What .class file did it see?
  • In which position of that class file did StringConcatFactory occur?
  • Why was that particular detail of the class file analysed?

@stephan-herrmann
Copy link
Contributor

@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
Copy link
Contributor

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

@mrj
Copy link

mrj commented Oct 1, 2024

The fix for me was to change the default-JRE tick from 1.8 to 22 in Preferences->Java->Installed JREs.

No change to a project's JRE and compatibility would substitute and remove these could-not-build errors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

10 participants