Backend Development 13 min read

Design and Implementation of an IntelliJ IDEA Plugin for Automatic HTTP Interface Invocation

This article describes how to build an IntelliJ IDEA plugin that parses Spring MVC controller code using PSI to automatically generate HTTP request definitions, handle method and parameter extraction, manage authentication cookies on macOS, and provides the complete source code and usage instructions.

政采云技术
政采云技术
政采云技术
Design and Implementation of an IntelliJ IDEA Plugin for Automatic HTTP Interface Invocation

Introduction

The author, a backend developer who frequently writes HTTP and Dubbo interfaces, became frustrated with manually creating Postman requests for each new endpoint and decided to automate the process by writing a plugin.

Design

The plugin extracts the following information from Spring MVC controllers:

URL path from @RequestMapping and related annotations on classes and methods.

HTTP method from @GetMapping , @PostMapping , @PutMapping , @DeleteMapping annotations.

Parameter definitions from method signatures, including names, types, and default values.

Authentication cookies required by the target domain.

Optional custom request headers for special scenarios such as CORS.

URL Parsing

Using the IntelliJ PSI (Program Structure Interface), the plugin scans PsiAnnotation objects to retrieve the mapping path. Example code:

private String pickMappingPath(PsiAnnotation[] psiAnnotations) {
    for (PsiAnnotation psiAnnotation : psiAnnotations) {
        SpringRestMappingAnnotationEnum annotationEnum = SpringRestMappingAnnotationEnum.getByAnnotation(psiAnnotation.getQualifiedName());
        if (Objects.isNull(annotationEnum)) {
            continue;
        }
        String text = psiAnnotation.findAttributeValue("value").getText();
        if (text.startsWith("\"")) {
            text = text.substring(1);
        }
        if (text.endsWith("\"")) {
            text = text.substring(0, text.length() - 1);
        }
        if (text.equals("{}")) {
            return "";
        }
        return text;
    }
    return "";
}

HTTP Method Parsing

The plugin determines the request method by inspecting method‑level annotations:

private String pickMethodMappingType(PsiMethod psiMethod) {
    for (PsiAnnotation psiAnnotation : psiMethod.getAnnotations()) {
        SpringRestMappingAnnotationEnum annotationEnum = SpringRestMappingAnnotationEnum.getByAnnotation(psiAnnotation.getQualifiedName());
        if (Objects.isNull(annotationEnum) || SpringRestMappingAnnotationEnum.DEFAULT.equals(annotationEnum)) {
            continue;
        }
        return annotationEnum.name();
    }
    return SpringRestMappingAnnotationEnum.GET.name();
}

Parameter Structure Parsing

Parameter information is obtained from PsiMethod and PsiParameter interfaces. The plugin builds a list of ParameterDesc objects with name, type, and default value:

private List
buildParameterDescs(PsiMethod psiMethod) {
    PsiParameter[] psiParameters = psiMethod.getParameterList().getParameters();
    List
parameterDescs = Lists.newArrayList();
    for (PsiParameter psiParameter : psiParameters) {
        ParameterDesc parameterDesc = ParameterDesc.builder()
            .name(psiParameter.getName())
            .type(psiParameter.getType().getClass())
            .defaultValue(PsiTypeUtil.getDefaultValue(psiParameter.getType()))
            .build();
        parameterDescs.add(parameterDesc);
    }
    return parameterDescs;
}

Default values for primitive, collection, map, enum, and custom types are resolved by the PsiTypeUtil.getDefaultValue method.

Cookie Extraction and Decoding

The plugin supports extracting cookies from Chrome and Microsoft Edge on macOS. Cookie data is stored in the SQLite database located at /Users/…/Library/Application Support/Google/Chrome/Default/Cookies . The decryption key is obtained from the macOS keychain using the following utility:

public class MacKeyringFetchUtil {
    public static Map
applicationKeyringMap = Maps.newHashMap();
    public static String getMacKeyringPassword(String application) throws IOException {
        if (applicationKeyringMap.containsKey(application)) {
            return applicationKeyringMap.get(application);
        }
        String[] commands = {"security", "find-generic-password", "-w", "-s", application};
        Process proc = Runtime.getRuntime().exec(commands);
        BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
        StringBuilder result = new StringBuilder();
        String s;
        while ((s = stdInput.readLine()) != null) {
            result.append(s);
        }
        String keyring = result.toString();
        applicationKeyringMap.put(application, keyring);
        return keyring;
    }
}

Decryption of the encrypted cookie value uses AES/CBC/PKCS5Padding with a key derived from the retrieved password:

private static String decryptedValue(BrowserEnum browserEnum, byte[] encryptedBytes) {
    byte[] decryptedBytes;
    try {
        byte[] salt = "saltysalt".getBytes();
        char[] password = browserEnum.fetchCookiesKeyring().toCharArray();
        char[] iv = new char[16];
        Arrays.fill(iv, ' ');
        int keyLength = 16;
        int iterations = 1003;
        PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, keyLength * 8);
        SecretKeyFactory pbkdf2 = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        byte[] aesKey = pbkdf2.generateSecret(spec).getEncoded();
        SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(new String(iv).getBytes()));
        String encryptedString = new String(encryptedBytes);
        if (encryptedString.startsWith("v10")) {
            encryptedBytes = Arrays.copyOfRange(encryptedBytes, 3, encryptedBytes.length);
        }
        decryptedBytes = cipher.doFinal(encryptedBytes);
    } catch (Exception e) {
        decryptedBytes = null;
    }
    return decryptedBytes == null ? null : new String(decryptedBytes);
}

Result

After implementing the above components, the author obtained a functional but simple plugin that can generate HTTP request definitions directly from Java controller code.

Project Repository

The source code is open‑source under GPL‑3.0 and can be found at https://github.com/threeone-wang/HttpInvokerIdeaPlugin . The README provides installation and usage instructions.

Recruitment Notice

The article concludes with a hiring call from the Zero team at Zhengcai Cloud, inviting interested engineers to contact [email protected] .

JavaSpring MVCIntelliJ PluginPSICookie ExtractionHTTP request
政采云技术
Written by

政采云技术

ZCY Technology Team (Zero), based in Hangzhou, is a growth-oriented team passionate about technology and craftsmanship. With around 500 members, we are building comprehensive engineering, project management, and talent development systems. We are committed to innovation and creating a cloud service ecosystem for government and enterprise procurement. We look forward to your joining us.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.