{"record":{"id":"be20fb5ac14d19a4","repo":"JetBrains/intellij-community","slug":"changesignature-contract-converter-external-annota","errorCode":"changeSignature.contract.converter.external.annotations","errorMessage":"Automatic update of external annotation is not supported","messagePattern":"Automatic update of external annotation is not supported","errorType":"exception","errorClass":"ContractConversionException","httpStatus":null,"severity":"error","filePath":"java/java-impl/src/com/intellij/refactoring/changeSignature/ContractConverter.java","lineNumber":36,"sourceCode":"import java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic final class ContractConverter {\n  private ContractConverter() {}\n\n  public static @Nullable PsiAnnotation convertContract(@NotNull PsiMethod method, @NotNull JavaChangeInfo info) throws ContractConversionException {\n    return convertContract(method, info.getOldParameterNames(), info.getNewParameters());\n  }\n\n  public static @Nullable PsiAnnotation convertContract(@NotNull PsiMethod method,\n                                                        String @NotNull [] oldParameterNames,\n                                                        JavaParameterInfo @NotNull [] newParameters) throws ContractConversionException {\n    PsiAnnotation annotation = JavaMethodContractUtil.findContractAnnotation(method);\n    if (annotation == null || AnnotationUtil.isInferredAnnotation(annotation)) return null;\n    if (AnnotationUtil.isExternalAnnotation(annotation)) {\n      throw new ContractConversionException(JavaRefactoringBundle.message(\"changeSignature.contract.converter.external.annotations\"));\n    }\n    if (annotation.getOwner() != method.getModifierList()) {\n      throw new ContractInheritedException();\n    }\n    if (annotation.findDeclaredAttributeValue(MutationSignature.ATTR_MUTATES) != null) {\n      throw new ContractConversionException(JavaRefactoringBundle.message(\"changeSignature.contract.converter.mutation.contract\"));\n    }\n    String text = AnnotationUtil.getStringAttributeValue(annotation, null);\n    List<StandardMethodContract> contracts = Collections.emptyList();\n    if (text != null) {\n      try {\n        contracts = StandardMethodContract.parseContract(text);\n      }\n      catch (StandardMethodContract.ParseException exception) {\n        String definitionError = JavaRefactoringBundle.message(\"changeSignature.contract.converter.definition.error\",\n                                                               exception.getMessage());\n        throw new ContractConversionException(definitionError);\n      }","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/JetBrains/intellij-community/blob/be881553f2a76ac8b4ea53950d93f0de78295c19/java/java-impl/src/com/intellij/refactoring/changeSignature/ContractConverter.java#L18-L54","documentation":"Thrown by ContractConverter.convertContract during Change Signature refactoring when a method's @org.jetbrains.annotations.Contract annotation is an external annotation (stored in an external annotations XML file rather than in the source). The IDE cannot automatically update external annotations, so the refactoring fails with ContractConversionException instead of silently leaving a stale contract.","triggerScenarios":"Running Change Signature on a method whose @Contract lives in external annotations (annotations/.../methods.xml next to a library, or an 'external annotations' directory configured in the module) while the signature change would require updating the contract.","commonSituations":"Projects that attach external annotations to third-party or read-only sources; libraries annotated via JetBrains external annotation sets; code where methods are annotated through an annotations repository rather than inline.","solutions":["Move the @Contract annotation into the source file (remove it from external annotations XML, add it above the method) and rerun Change Signature.","Manually update the contract clause in the external annotations XML to match the new parameter order, then skip automatic conversion.","Perform the signature change without contract conversion and fix the contract yourself afterwards.","Exclude the annotated method from refactoring or revert parameter reordering that affects contract clauses."],"exampleFix":"// before: external annotations XML\n<method ...><annotation name='org.jetbrains.annotations.Contract'><val name='value' val='null -> false'/></annotation></method>\n// after: inline in source\nimport org.jetbrains.annotations.Contract;\n@Contract(\"null -> false\")\npublic boolean check(@Nullable String s) { ... }","handlingStrategy":"try-catch","validationCode":"PsiAnnotation ann = JavaMethodContractUtil.findContractAnnotation(method);\nif (ann != null && AnnotationUtil.isExternalAnnotation(ann)) {\n  // update external annotations XML manually or inline the annotation first\n}","typeGuard":"static boolean isInlineContract(@NotNull PsiMethod m) {\n  PsiAnnotation a = JavaMethodContractUtil.findContractAnnotation(m);\n  return a == null || (!AnnotationUtil.isExternalAnnotation(a) && !AnnotationUtil.isInferredAnnotation(a) && a.getOwner() == m.getModifierList());\n}","tryCatchPattern":"try { ContractConverter.convertContract(method, info); } catch (ContractConversionException e) { /* show message; for external annotations update the XML by hand */ }","preventionTips":["Keep @Contract annotations inline in sources for methods you plan to refactor.","Before Change Signature, check whether the contract comes from external annotations (annotation gutter icon / AnnotationUtil.isExternalAnnotation).","Track external annotation XML in VCS and update it together with signature changes."],"tags":["java","refactoring","change-signature","contract-annotation","external-annotations"],"backgroundTag":null,"analyzedSha":"be881553f2a76ac8b4ea53950d93f0de78295c19","analyzedAt":"2026-08-14T14:13:06.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}