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.
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] .
政采云技术
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.