diff --git a/org.eclipse.jdt.apt.pluggable.tests/plugin.xml b/org.eclipse.jdt.apt.pluggable.tests/plugin.xml
index ced29d71d8b..3c53cb4b616 100644
--- a/org.eclipse.jdt.apt.pluggable.tests/plugin.xml
+++ b/org.eclipse.jdt.apt.pluggable.tests/plugin.xml
@@ -59,6 +59,9 @@
+
+
diff --git a/org.eclipse.jdt.apt.pluggable.tests/resources/targets/issue565/A.java b/org.eclipse.jdt.apt.pluggable.tests/resources/targets/issue565/A.java
new file mode 100644
index 00000000000..44d5090f17a
--- /dev/null
+++ b/org.eclipse.jdt.apt.pluggable.tests/resources/targets/issue565/A.java
@@ -0,0 +1,5 @@
+package targets.issue565;
+import java.io.Serializable;
+
+@Annotation565
+public class A & Runnable>{}
diff --git a/org.eclipse.jdt.apt.pluggable.tests/resources/targets/issue565/Annotation565.java b/org.eclipse.jdt.apt.pluggable.tests/resources/targets/issue565/Annotation565.java
new file mode 100644
index 00000000000..6d3196c929c
--- /dev/null
+++ b/org.eclipse.jdt.apt.pluggable.tests/resources/targets/issue565/Annotation565.java
@@ -0,0 +1,6 @@
+package targets.issue565;
+import java.lang.annotation.Inherited;
+
+@Inherited
+public @interface Annotation565 {
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/BuilderTests.java b/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/BuilderTests.java
index fa80b4239ee..9fecb3bfc49 100644
--- a/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/BuilderTests.java
+++ b/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/BuilderTests.java
@@ -25,6 +25,7 @@
import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.Bug341298Processor;
import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.Bug468893Processor;
import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.Bug510118Processor;
+import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.Issue565Processor;
import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.BugsProc;
import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.InheritedAnnoProc;
import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.TestFinalRoundProc;
@@ -370,6 +371,19 @@ public void testBug510118() throws Throwable {
assertTrue("Incorrect status received from annotation processor", Bug510118Processor.status());
}
+ public void testIssue565() throws Throwable {
+ ProcessorTestStatus.reset();
+ IJavaProject jproj = createJavaProject(_projectName);
+ disableJava5Factories(jproj);
+ IProject proj = jproj.getProject();
+ IdeTestUtils.copyResources(proj, "targets/issue565", "src/targets/issue565");
+
+ AptConfig.setEnabled(jproj, true);
+ fullBuild();
+ expectingNoProblems();
+ assertTrue("Incorrect status received from annotation processor", Issue565Processor.status());
+ }
+
public void testBug341298() throws Throwable {
ProcessorTestStatus.reset();
IJavaProject project = createJavaProject(_projectName);
diff --git a/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/processors/buildertester/Issue565Processor.java b/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/processors/buildertester/Issue565Processor.java
new file mode 100644
index 00000000000..de81942ff82
--- /dev/null
+++ b/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/processors/buildertester/Issue565Processor.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Kamil Krzywanski
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Kamil Krzywanski - initial creation if Interesection type and Implementation
+ *******************************************************************************/
+package org.eclipse.jdt.apt.pluggable.tests.processors.buildertester;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.*;
+import javax.lang.model.util.SimpleTypeVisitor8;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+@SupportedAnnotationTypes("targets.issue565.Annotation565")
+@SupportedSourceVersion(SourceVersion.RELEASE_6)
+public class Issue565Processor extends AbstractProcessor {
+ private static boolean status = false;
+
+ @Override
+ public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (roundEnv.processingOver()) {
+ // We're not interested in the postprocessing round.
+ return false;
+ }
+
+ for (Element element : roundEnv.getElementsAnnotatedWith(annotations.stream().findAny().get())) {
+ if (element instanceof TypeElement) {
+ keyBuilder.visit(element.asType(), true);
+ }
+ }
+ status = true;
+ return false;
+ }
+
+ public static boolean status() {
+ return status;
+ }
+
+ // This is a fragment of querydsl visitor
+ private final TypeVisitor, Boolean> keyBuilder = new SimpleTypeVisitor8<>() {
+ private final List defaultValue = Collections.singletonList("Object");
+
+ private List visitBase(TypeMirror t) {
+ List rv = new ArrayList<>();
+ String name = t.toString();
+ if (name.contains("<")) {
+ name = name.substring(0, name.indexOf('<'));
+ }
+ rv.add(name);
+ return rv;
+ }
+
+ @Override
+ public List visitDeclared(DeclaredType t, Boolean p) {
+ List rv = visitBase(t);
+ for (TypeMirror arg : t.getTypeArguments()) {
+ if (p) {
+ rv.addAll(visit(arg, false));
+ } else {
+ rv.add(arg.toString());
+ }
+ }
+ return rv;
+ }
+
+ @Override
+ public List visitTypeVariable(TypeVariable t, Boolean p) {
+ List rv = visitBase(t);
+ if (t.getUpperBound() != null) {
+ rv.addAll(visit(t.getUpperBound(), p));
+ }
+ if (t.getLowerBound() != null) {
+ rv.addAll(visit(t.getLowerBound(), p));
+ }
+ return rv;
+ }
+
+ @Override
+ public List visitIntersection(IntersectionType t, Boolean p) {
+ return t.getBounds().get(0).accept(this, p);
+ }
+
+ @Override
+ public List visitNull(NullType t, Boolean p) {
+ return defaultValue;
+ }
+ };
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/IntersectionTypeImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/IntersectionTypeImpl.java
new file mode 100644
index 00000000000..3874f7d4b3c
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/IntersectionTypeImpl.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Kamil Krzywanski and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Kamil Krzywanski - initial creation if Interesection type and Implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+
+import javax.lang.model.type.IntersectionType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVisitor;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Implementation of the WildcardType
+ */
+public class IntersectionTypeImpl extends TypeMirrorImpl implements IntersectionType {
+ private final List extends TypeMirror> bounds;
+
+ IntersectionTypeImpl(BaseProcessingEnvImpl env, TypeVariableBinding binding) {
+ super(env, binding);
+ this.bounds = Arrays.stream(binding.superInterfaces).map(referenceBinding -> this._env.getFactory().newTypeMirror(referenceBinding)).toList();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#getKind()
+ */
+ @Override
+ public TypeKind getKind() {
+ return TypeKind.INTERSECTION;
+ }
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.WildcardType#getSuperBound()
+ */
+ @Override
+ public R accept(TypeVisitor v, P p) {
+ return v.visitIntersection(this, p);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.IntersectionType#getBounds()
+ */
+ @Override
+ public List extends TypeMirror> getBounds() {
+ return this.bounds;
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypeVariableImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypeVariableImpl.java
index 46a6d7e1990..b4f293f2b48 100644
--- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypeVariableImpl.java
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypeVariableImpl.java
@@ -66,6 +66,10 @@ public TypeMirror getUpperBound() {
// only one bound that is an interface
return this._env.getFactory().newTypeMirror(typeVariableBinding.upperBound());
}
+ if (superInterfaces.length > 1) {
+ return new IntersectionTypeImpl(this._env, typeVariableBinding);
+ }
+
return this._env.getFactory().newTypeMirror(this._binding);
}