Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ public interface MethodModel extends Member, AnnotatedElement {
*/
String[] getArgumentTypes();

/**
* @return the checked exception types, or an empty array if the method doesn't
* declare any thrown exceptions
*/
String[] getExceptionTypes();

/**
* Returns the list of parameter
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
public class MethodModelImpl extends AnnotatedElementImpl implements MethodModel {

private List<Parameter> parameters;
private List<ParameterizedType> exceptionTypes;
private ParameterizedType returnType;
final ExtensibleType<?> owner;
private final String signature;
Expand Down Expand Up @@ -74,6 +75,24 @@ public String[] getArgumentTypes() {
return stringTypes;
}

@Override
public String[] getExceptionTypes() {
String[] stringTypes;
if (exceptionTypes != null) {
stringTypes = new String[exceptionTypes.size()];
for (int i = 0; i < exceptionTypes.size(); i++) {
stringTypes[i] = exceptionTypes.get(i).getTypeName();
}
} else {
stringTypes = new String[0];
}
return stringTypes;
}

public void setExceptionTypes(List<ParameterizedType> exceptionTypes) {
this.exceptionTypes = exceptionTypes;
}

@Override
public List<Parameter> getParameters() {
return parameters;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public class MethodSignatureVisitorImpl extends SignatureVisitor {
private final MethodModel methodModel;

private final List<Parameter> parameters = new ArrayList<>();
private final List<ParameterizedType> exceptionTypes = new ArrayList<>();
private final ParameterizedType returnType = new ParameterizedTypeImpl();
private final ArrayDeque<ParameterizedType> parentType = new ArrayDeque<>();

Expand All @@ -50,6 +51,10 @@ public List<Parameter> getParameters() {
return parameters;
}

public List<ParameterizedType> getExceptionTypes() {
return exceptionTypes;
}

public ParameterizedType getReturnType() {
return returnType;
}
Expand All @@ -62,6 +67,14 @@ public SignatureVisitor visitParameterType() {
return this;
}

@Override
public SignatureVisitor visitExceptionType() {
ParameterizedTypeImpl exceptionType = new ParameterizedTypeImpl();
exceptionTypes.add(exceptionType);
parentType.add(exceptionType);
return this;
Copy link
Contributor

@pzygielo pzygielo May 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't exceptionTypes be updated somewhere, perhaps here? Otherwise - how it gets populated?

Edit: I've removed locally this method and collection+getter and the test is fine with such change. Do we need exceptionTypes in this class?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @pzygielo. This code doesn't do anything right now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will review - I was simply cherry-picking from our fork (I didn't make the original change)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an inherited method from the SignatureVisitor class from ASM: SignatureVisitor#L153.

There is an identical implementation of it over in the SignatureVisitorImpl class here in HK2: SignatureVisitorImpl#L88.

So I assume the original intent was to simply mirror the behaviour of the SignatureVisitorImpl class.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be to follow established pattern, right.
What would be the role of exceptionTypes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would need to spend some time digging into it with a debugger - it's a bit abstract for my eyes to dry-run through.

The interface method from MethodModel (and presumably MethodModelImpl) gets used over in Payara for MicroProfile OpenAPI processing here and here.

Within HK2 itself the important changes within this PR seem to be working on the MethodModel within the ModelClassVisitor (here). This code is preceded by reading the method signature (which is where this MethodSignatureVisitorImpl class comes into play), during which at least one code path seems to "visit" the exception type (which is where I start getting lost without a debugger).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Pandrex247, list exceptionTypes at L39 always stay empty because it never updated.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

list exceptionTypes at L39 always stay empty because it never updated.

Probably we don't know. getExceptionTypes returns original, mutable list so this MIGHT be updated anywhere, out of control of the class.
I understand getParameters does the same.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand getParameters does the same.

But parameters collection is filled in the visitParameterType() method at L63 of the MethodSignatureVisitorImpl class.

Actual exception types processing occurs in the ModelClassVisitor class beginnin with L284.

mutable list so this MIGHT be updated anywhere, out of control of the class.

In this case even out of control HK2.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current solution seems to work, the test passes. I debugged it now and found out that ASM doesn't pass info about exceptions in the signature argument to visitMethod of ModelClassVisitor. It only passes the info in the separate argument exceptions.

As a result, the method visitExceptionType here is never called. That's why it isn't enough to implement it.

However, I managed to get it working by manually calling the visitExceptionType() and then visitClassType methods on the visitor for each exception in the visitMethod class, right after the visitor is called by ASM signature reader. With this, things work as they should and the code is in line with the existing code, just with some help to the ASM SignatureReader, which doesn't find info about exceptions in the signature.

Here's are the changes: https://github.com/Pandrex247/glassfish-hk2/compare/Add-Exception-Type-Parsing...OndroMih:glassfish-hk2:ondromih-Add-Exception-Type-Parsing?expand=1

If it's OK like this, we can accept this PR and then I'll raise another PR with my improvements.

}

@Override
public SignatureVisitor visitReturnType() {
parentType.add(returnType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
public class ModelClassVisitor extends ClassVisitor {

private static Logger logger = Logger.getLogger(ModelClassVisitor.class.getName());

private final ParsingContext ctx;
private final TypeBuilder typeBuilder;
private final URI definingURI;
Expand All @@ -60,7 +60,7 @@ public class ModelClassVisitor extends ClassVisitor {
public ModelClassVisitor(ParsingContext ctx, URI definingURI, String entryName,
boolean isApplicationClass) {
super(Opcodes.ASM9);

this.ctx = ctx;
this.definingURI = definingURI;
this.entryName = entryName;
Expand All @@ -83,7 +83,7 @@ public void visit(int version, int access, String name, String signature, String
parent = (parentName!=null?typeBuilder.getHolder(parentName, typeType):null);
}
if (parent!=null && !parentName.equals(Object.class.getName())) {
// put a temporary parent until we eventually visit it.
// put a temporary parent until we eventually visit it.
TypeImpl parentType = typeBuilder.getType(access, parentName, null);
parent.set(parentType);
}
Expand All @@ -100,15 +100,15 @@ public void visit(int version, int access, String name, String signature, String
} catch (URISyntaxException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}

if (logger.isLoggable(Level.FINER)) {
logger.log(Level.FINER, "visiting {0} with classDefURI={1}", new Object[] {entryName, classDefURI});
}

// if (!new File(classDefURI).exists()) {
// throw new IllegalStateException(entryName + ": " + classDefURI.toString());
// }

type = ctx.getTypeBuilder(classDefURI).getType(access, className, parent);
type.setApplicationClass(isApplicationClass);
type.getProxy().visited();
Expand Down Expand Up @@ -151,7 +151,7 @@ public void visit(int version, int access, String name, String signature, String
if (typeProxy.get() == null) {
typeProxy.set((InterfaceModel) interfaceModel);
}

classModel.isImplementing(typeProxy);
if (classModel instanceof ClassModel) {
typeProxy.addImplementation((ClassModel) classModel);
Expand Down Expand Up @@ -180,7 +180,7 @@ public void visitOuterClass(String owner, String name, String desc) {
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
desc = unwrap(desc);

final AnnotationTypeImpl at = (AnnotationTypeImpl) typeBuilder.getType(Opcodes.ACC_ANNOTATION, desc, null);
final AnnotationModelImpl am = new AnnotationModelImpl(type, at);

Expand Down Expand Up @@ -271,10 +271,11 @@ public MethodVisitor visitMethod(int access, String name, String desc, String si

SignatureReader reader = new SignatureReader(signature == null ? desc : signature);
MethodSignatureVisitorImpl visitor = new MethodSignatureVisitorImpl(typeBuilder, methodModel);
reader.accept(visitor);
acceptSignatureAndExceptions(reader, exceptions, visitor);

methodModel.setParameters(visitor.getParameters());
methodModel.setReturnType(visitor.getReturnType());
methodModel.setExceptionTypes(visitor.getExceptionTypes());

// fallback for void, primitive data types, java.lang.Object and generic wildcards types
ParameterizedTypeImpl returnType = (ParameterizedTypeImpl) methodModel.getReturnType();
Expand All @@ -291,10 +292,22 @@ public MethodVisitor visitMethod(int access, String name, String desc, String si
return methodVisitor;
}

private void acceptSignatureAndExceptions(SignatureReader reader, String[] exceptions, MethodSignatureVisitorImpl visitor) {
reader.accept(visitor);
// if info about exceptions isn't in the signature and the visitor didn't receive it,
// pass this info from the exceptions array
if (exceptions != null && visitor.getExceptionTypes().isEmpty()) {
for (String exceptionType : exceptions) {
visitor.visitExceptionType();
visitor.visitClassType(exceptionType);
}
}
}

@Override
public void visitEnd() {
type=null;
}
}

private String unwrap(String desc) {
return org.objectweb.asm.Type.getType(desc).getClassName();
Expand Down Expand Up @@ -344,7 +357,7 @@ private class ModelMethodVisitor extends MethodVisitor {

private ModelMethodVisitor(MemberVisitingContext context) {
super(Opcodes.ASM9);

this.context = new MethodVisitingContext(context.modelUnAnnotatedMembers);
}

Expand All @@ -358,7 +371,7 @@ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
// probably an annotation method, ignore
return null;
}

AnnotationTypeImpl annotationType = (AnnotationTypeImpl) typeBuilder.getType(Opcodes.ACC_ANNOTATION, unwrap(desc), null);
AnnotationModelImpl annotationModel = new AnnotationModelImpl(context.method, annotationType);

Expand Down Expand Up @@ -405,8 +418,8 @@ public AnnotationVisitor visitAnnotationDefault() {
return defaultAnnotationVisitor;
}
}


private class ModelDefaultAnnotationVisitor extends AnnotationVisitor {

private final MethodVisitingContext context;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ public void simpleTest() throws IOException, InterruptedException {
Assert.assertEquals("yellow", gradientColor2.get(0).getValues().get("name"));
Assert.assertEquals("orange", gradientColor2.get(1).getValues().get("name"));

// Exception types
final String[] exceptionTypes = mm.getExceptionTypes();
Assert.assertEquals(1, exceptionTypes.length);
Assert.assertEquals(IllegalArgumentException.class.getName(), exceptionTypes[0]);

// Parameter annotations, type and generic types check
Assert.assertEquals(5, mm.getParameters().size());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public SampleType<Integer, Character, Boolean> setFoo(
List<String> input,
SampleType<Double, String, SampleType<Short, Float, Long>> sampleType,
int count,
Object value) {
Object value) throws IllegalArgumentException {
return null;
}
}
Expand Down