
com.github.bingoohuang.springrestclient.generators.ClassGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spring-rest-client Show documentation
Show all versions of spring-rest-client Show documentation
convenient spring rest client for rest services
package com.github.bingoohuang.springrestclient.generators;
import com.github.bingoohuang.springrestclient.annotations.SpringRestClientEnabled;
import com.github.bingoohuang.springrestclient.annotations.SuccInResponseJSONProperty;
import com.github.bingoohuang.springrestclient.provider.BaseUrlProvider;
import com.github.bingoohuang.springrestclient.provider.SignProvider;
import com.google.common.io.Files;
import lombok.val;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Map;
import static com.github.bingoohuang.springrestclient.utils.Asms.ci;
import static com.github.bingoohuang.springrestclient.utils.Asms.p;
import static org.objectweb.asm.Opcodes.*;
public class ClassGenerator {
private final Class restClientClass;
private final String implName;
private final ClassWriter classWriter;
private final SpringRestClientEnabled restClientEnabled;
public ClassGenerator(Class restClientClass) {
this.restClientClass = restClientClass;
this.implName = restClientClass.getName() + "$$BINGOOASM$$Impl";
this.classWriter = createClassWriter();
this.restClientEnabled = restClientClass.getAnnotation(SpringRestClientEnabled.class);
}
public Class extends T> generate() {
byte[] bytes = createImplClassBytes();
createClassFileForDiagnose(bytes);
return defineClass(bytes);
}
public String getClassRequestMapping() {
val re = restClientClass.getAnnotation(RequestMapping.class);
return re != null && re.value().length > 0 ? re.value()[0] : "";
}
private void createClassFileForDiagnose(byte[] bytes) {
if (restClientEnabled.createClassFileForDiagnose())
writeClassFile4Diagnose(bytes, implName + ".class");
}
private void writeClassFile4Diagnose(byte[] bytes, String fileName) {
try {
Files.write(bytes, new File(fileName));
} catch (IOException e) {
// ignore
}
}
private Class extends T> defineClass(byte[] bytes) {
val parentClassLoader = restClientClass.getClassLoader();
val classLoader = new RestClientClassLoader(parentClassLoader);
return (Class extends T>) classLoader.defineClass(implName, bytes);
}
private byte[] createImplClassBytes() {
String classRequestMapping = getClassRequestMapping();
constructor();
for (Method method : restClientClass.getMethods()) {
new MethodGenerator(classWriter, implName, method, classRequestMapping).generate();
}
return createBytes();
}
private byte[] createBytes() {
classWriter.visitEnd();
return classWriter.toByteArray();
}
private ClassWriter createClassWriter() {
val cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
String[] interfaces = {Type.getInternalName(restClientClass)};
cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, implName.replace('.', '/'), null, p(Object.class), interfaces);
FieldVisitor fv = cw.visitField(0, MethodGenerator.baseUrlProvider, ci(BaseUrlProvider.class), null, null);
fv.visitEnd();
fv = cw.visitField(0, MethodGenerator.signProvider, ci(SignProvider.class), null, null);
fv.visitEnd();
fv = cw.visitField(0, MethodGenerator.appContext, ci(ApplicationContext.class), null, null);
fv.visitEnd();
for (Method method : restClientClass.getDeclaredMethods()) {
fv = cw.visitField(0, method.getName() + MethodGenerator.StatusExceptionMappings,
ci(Map.class), null, null);
fv.visitEnd();
fv = cw.visitField(0, method.getName() + MethodGenerator.FixedRequestParams,
ci(Map.class), null, null);
fv.visitEnd();
fv = cw.visitField(0, method.getName() + MethodGenerator.SuccInResponseJSONProperty,
ci(SuccInResponseJSONProperty.class), null, null);
fv.visitEnd();
}
return cw;
}
private void constructor() {
MethodVisitor mv = classWriter.visitMethod(ACC_PUBLIC, "", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, p(Object.class), "", "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy