Skip to content

[Bug]: SniperPrettyPrinter - abnormal annotation print behavior #6451

@beijiaxu

Description

@beijiaxu

Describe the bug

I encounter 2 issues that are very strange, but I can't locate problem, I'll provide the detail code as much as possible.

Issues:

  • ModificationStatus throws IllegalStateException
    • the error occurs in code line 32 in Source code for issue 1, the scanner detects SentinelAdminConsoleResponseListPolicySummary.class changes, and save to changedRole
    • Then while entering method spoon.support.sniper.internal.AbstractSourceFragmentPrinter#isFragmentModified in condition fragment instanceof ElementSourceFragment, it returns true, then code goes to SniperJavaPrettyPrinter, listContext.print(this);, not the normal condition to NOT_MODIFIED and directPrint
    • Then the annotation's CollectionSourceFragement still goes to printSourceFragment, and get ModificationStatus to UNKNOWN
  • annotation parsed tokens return invalid position, but now I can't find the project to reproduce
    • e.g: ElementSourceFragement:667, throw new SpoonException("Inconsistent start/end. Start=" + start + " is greater then End=" + end);

Source code for issue 1:


import com.app.gen.model.*;
import com.jaxrs.server.ResourceOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.annotation.Generated;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.*;
import org.springframework.security.access.prepost.PreAuthorize;

@Generated(value = "com.swagger.templates.codegen.JavaEtsGenerator", date = "2025-09-17T13:49:15.349462+08:00[Asia/Shanghai]")
public interface PolicyResourceApi {
    @Schema(implementation = SentinelAdminConsoleResponseListPolicySummary.class)
    @Generated(value = "123", date = "2025-09-17T13:49:15.349462+08:00[Asia/Shanghai]")
    @POST
    @Path("/llm")
    @Consumes({ "application/json" })
    @Produces({ "application/json" })
    Response aBTest(@Context ContainerRequestContext requestContext, CheckConnectionRequest body);
}```

### Source code you are trying to analyze/transform

```Java
CtType typeB = ctModel.getAllTypes().stream().filter(t -> t.getQualifiedName().equals("com.B")).toList().get(0);

ctModel.getElements(new TypeFilter<>(CtTypeReference.class) {
            @Override
            public boolean matches(CtTypeReference element) {
                return element.getQualifiedName().equals("com.A") && !element.isImplicit();
            }
        }).forEach(ref -> {

             ref.replace(typeB.getReference());
});

Source code for your Spoon processing

launcher.getEnvironment().setNoClasspath(true);
            launcher.getEnvironment().setIgnoreDuplicateDeclarations(true);
            launcher.getEnvironment().setPrettyPrinterCreator(() -> {
                SniperJavaPrettyPrinter printer = new SniperJavaPrettyPrinter(launcher.getEnvironment());
                List<Processor<CtElement>> preprocessors = List.of(
                        //try to import as much types as possible
                        new ForceImportProcessor(),
                        //remove unused imports first. Do not add new imports at time when conflicts are not resolved
                        new ImportCleaner().setCanAddImports(false),
                        //solve conflicts, the current imports are relevant too
                        new ImportConflictDetector(),
                        //compute final imports
                        new ImportCleaner().setImportComparator(new DefaultImportComparator())
                );
                printer.setIgnoreImplicit(false);
                printer.setPreprocessors(preprocessors);
                return printer;
            });

Actual output

Expected output

Spoon Version

11.2.1

JVM Version

17

What operating system are you using?

mac 15.4.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions