{"record":{"id":"ab46a7a7d2fd31c4","repo":"spring-projects/spring-ai","slug":"this-is-a-utility-class-and-cannot-be-instantiated","errorCode":null,"errorMessage":"This is a utility class and cannot be instantiated","messagePattern":"This is a utility class and cannot be instantiated","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"warning","filePath":"spring-ai-model/src/main/java/org/springframework/ai/support/UsageCalculator.java","lineNumber":35,"sourceCode":"package org.springframework.ai.support;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.ai.chat.metadata.ChatResponseMetadata;\nimport org.springframework.ai.chat.metadata.DefaultUsage;\nimport org.springframework.ai.chat.metadata.Usage;\nimport org.springframework.ai.chat.model.ChatResponse;\n\n/**\n * A utility class to provide support methods handling {@link Usage}.\n *\n * @author Ilayaperumal Gopinathan\n * @author Jewoo Shin\n */\npublic final class UsageCalculator {\n\n\tprivate UsageCalculator() {\n\t\tthrow new UnsupportedOperationException(\"This is a utility class and cannot be instantiated\");\n\t}\n\n\t/**\n\t * Accumulate usage tokens from the previous chat response to the current usage\n\t * tokens.\n\t * <p>\n\t * Note: when the two usages are actually summed, the result is a plain\n\t * {@link DefaultUsage} and the provider-specific {@link Usage#getNativeUsage() native\n\t * usage} object is <em>not</em> preserved (it cannot be merged across responses).\n\t * Only the token counts and cache metrics carry over. The original\n\t * {@code currentUsage} (native usage included) is returned unchanged when there is\n\t * nothing to accumulate.\n\t * @param currentUsage the current usage.\n\t * @param previousChatResponse the previous chat response.\n\t * @return accumulated usage.\n\t */\n\tpublic static Usage getCumulativeUsage(final Usage currentUsage,\n\t\t\tfinal @Nullable ChatResponse previousChatResponse) {","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/spring-ai-model/src/main/java/org/springframework/ai/support/UsageCalculator.java#L17-L53","documentation":"UsageCalculator is a final utility class whose private constructor deliberately throws UnsupportedOperationException(\"This is a utility class and cannot be instantiated\"). It only offers static methods (e.g. accumulateUsage), so instantiation is a programming mistake. The library throws this to enforce the utility-class pattern.","triggerScenarios":"Calling new UsageCalculator() directly, or invoking reflection/bean-wiring that attempts to instantiate the class instead of using its static methods.","commonSituations":"Registering UsageCalculator as a Spring bean by mistake, copying code that instantiates other helper classes, or IDE auto-import followed by 'new UsageCalculator()'.","solutions":["Use the static methods directly, e.g. UsageCalculator.getUsage(previousResponse, currentResponse)","Remove any @Bean/@Component registration or 'new UsageCalculator()' usage","If wiring is needed, wrap it in your own service class instead of instantiating it"],"exampleFix":"// before\nUsageCalculator calc = new UsageCalculator();\nUsage usage = calc.getUsage(prev, curr);\n// after\nUsage usage = UsageCalculator.getUsage(prev, curr);","handlingStrategy":"type-guard","validationCode":"// Never instantiate; detect accidental reflective instantiation early\nif (UsageCalculator.class.getDeclaredConstructors().length > 0) { /* utility class, use statics */ }","typeGuard":"boolean isUtilityClassMisuse = false;\ntry { UsageCalculator.class.getDeclaredConstructor().newInstance(); isUtilityClassMisuse = true; }\ncatch (ReflectiveOperationException ignored) { }\n// isUtilityClassMisuse == true means someone tried to instantiate it","tryCatchPattern":"try {\n    Usage usage = UsageCalculator.getUsage(prev, curr);\n} catch (UnsupportedOperationException e) {\n    // you instantiated the utility class somewhere; fix the call site\n    throw new AssertionError(\"Use UsageCalculator static methods\", e);\n}","preventionTips":["Call static methods on the class directly","Never register utility classes as Spring beans","Watch for IDE auto-completion offering a constructor"],"tags":["spring-ai","utility-class","misuse","instantiation"],"backgroundTag":"unsupported-operation","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}