博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java使用bytebuddy动态生成带泛型的DTO
阅读量:7239 次
发布时间:2019-06-29

本文共 19608 字,大约阅读时间需要 65 分钟。

hot3.png

我这人文笔很low,喜欢直接贴代码,大家将就着看

//TODO 文字描述,回头有空再补上

package com.valsong.bytebuddy;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.TypeReference;import com.valsong.dto.User;import net.bytebuddy.ByteBuddy;import net.bytebuddy.NamingStrategy;import net.bytebuddy.description.annotation.AnnotationDescription;import net.bytebuddy.description.annotation.AnnotationSource;import net.bytebuddy.description.type.TypeDefinition;import net.bytebuddy.description.type.TypeDescription;import net.bytebuddy.dynamic.DynamicType;import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;import net.bytebuddy.implementation.MethodDelegation;import net.bytebuddy.implementation.bind.annotation.Argument;import org.junit.jupiter.api.Assertions;import org.junit.jupiter.api.Test;import java.io.File;import java.io.IOException;import java.lang.annotation.Annotation;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.lang.reflect.Type;import java.util.ArrayList;import java.util.LinkedHashMap;import java.util.List;import java.util.Map;import java.util.Optional;/** * byte buddy 创建简单的class */public class ByteBuddyTest {    /**     * 构建     *     * package net.bytebuddy.renamed.java.lang.Object$com.valsong.dynamicdto;     *     * public class User$zulHzyXk {     *     private String name;     *     private Integer age;     *     *     public void setName(String var1) {     *         this.name = var1;     *     }     *     *     public String getName() {     *         return this.name;     *     }     *     *     public void setAge(Integer var1) {     *         this.age = var1;     *     }     *     *     public Integer getAge() {     *         return this.age;     *     }     *     *     public User$zulHzyXk() {     *     }     * }     *      */    @Test    public void makeSimpleDto() {        DynamicType.Builder dynamicBuilder = new ByteBuddy()                //指定前缀                .with(new NamingStrategy.SuffixingRandom("com.valsong.dynamicdto.User"))                .subclass(Object.class)                //.name("com.valsong.dynamicdto.User")                .defineProperty("name", String.class)                .defineProperty("age", Integer.class);        DynamicType.Unloaded
dynamicType = dynamicBuilder.make(); saveAndLoad(dynamicType); } /** * 构建 *

* package com.valsong.dynamicdto; *

* import com.valsong.bytebuddy.MyAnnotation; * * @MyAnnotation( name = "House", * value = "House", * required = false * ) * public class House { * @MyAnnotation( name = "address", * value = "china shanghai", * required = true * ) * private String address; * @MyAnnotation( name = "area", * value = "100", * required = true * ) * private Double area; *

* public void setAddress(String var1) { * this.address = var1; * } *

* public String getAddress() { * return this.address; * } *

* public void setArea(Double var1) { * this.area = var1; * } *

* public Double getArea() { * return this.area; * } *

* public House() { * } * } */ @Test public void makeSimpleDtoWithAnnotation() { MyAnnotation myAnnotation = new MyAnnotation() { @Override public Class

annotationType() { return MyAnnotation.class; } @Override public String value() { return "House"; } @Override public String name() { return "House"; } @Override public boolean required() { return false; } }; AnnotationDescription apiModelPropertyDescription1 = AnnotationDescription.Builder.ofType(MyAnnotation.class) .define("value", "china shanghai") .define("name", "address") .define("required", true) .build(); //将MyAnnotation注解转化成apiModelPropertyDescription AnnotationDescription apiModelPropertyDescription2 = AnnotationDescription.Builder.ofType(MyAnnotation.class) .define("value", "100") .define("name", "area") .define("required", true) .build(); DynamicType.Builder dynamicBuilder = new ByteBuddy() .subclass(Object.class) .name("com.valsong.dynamicdto.House") .annotateType(myAnnotation) .defineProperty("address", String.class) .annotateField(apiModelPropertyDescription1) .defineProperty("area", Double.class) .annotateField(apiModelPropertyDescription2); DynamicType.Unloaded
dynamicType = dynamicBuilder.make(); saveAndLoad(dynamicType); } /** * 构建 *

* package com.valsong.dynamicdto; *

* import java.util.Map; *

* public class MapContainer { * private Map

map; *

* public void setMap(Map

var1) { * this.map = var1; * } *

* public Map

getMap() { * return this.map; * } *

* public MapContainer() { * } * } * * @throws ClassNotFoundException */ @Test public void makeGenericMapDto() throws ClassNotFoundException { Class

rawType = Map.class; List
typeArgumentsDefinitions = new ArrayList<>(2); typeArgumentsDefinitions.add(new TypeDescription.ForLoadedType(String.class)); typeArgumentsDefinitions.add(new TypeDescription.ForLoadedType(Object.class)); //ownerType泛型 TypeDescription.Generic ownerTypeGeneric = Optional.ofNullable(rawType.getDeclaringClass()) .map(TypeDefinition.Sort::describe) .orElse(null); //Map
TypeDefinition mapField = TypeDescription.Generic.Builder.parameterizedType( //TypeDescription.ForLoadedType.of(rawType) //为了解决版本冲突将bytebuddy版本改成了1.7.11 new TypeDescription.ForLoadedType(rawType) , ownerTypeGeneric, typeArgumentsDefinitions).build(); DynamicType.Builder dynamicBuilder = new ByteBuddy() .subclass(Object.class) .name("com.valsong.dynamicdto.MapContainer") .defineProperty("map", mapField); DynamicType.Unloaded
dynamicType = dynamicBuilder.make(); saveAndLoad(dynamicType); } /** * 构建 *

* package com.valsong.dynamicdto; *

* import java.util.List; *

* public class ListArrayContainer { * private List

[] listArray; *

* public void setListArray(List

[] var1) { * this.listArray = var1; * } *

* public List

[] getListArray() { * return this.listArray; * } *

* public ListArrayContainer() { * } * } * * @throws ClassNotFoundException */ @Test public void makeGenericArrayType() throws ClassNotFoundException { Class

rawType = List.class; List
typeArgumentsDefinitions = new ArrayList<>(2); typeArgumentsDefinitions.add(new TypeDescription.ForLoadedType(String.class)); //ownerType泛型 TypeDescription.Generic ownerTypeGeneric = Optional.ofNullable(rawType.getDeclaringClass()) .map(TypeDefinition.Sort::describe) .orElse(null); //List
[] TypeDefinition listArrayField = TypeDescription.Generic.Builder.parameterizedType( //TypeDescription.ForLoadedType.of(rawType) //为了解决版本冲突将bytebuddy版本改成了1.7.11 new TypeDescription.ForLoadedType(rawType) , ownerTypeGeneric, typeArgumentsDefinitions) .asArray() .build(); DynamicType.Builder dynamicBuilder = new ByteBuddy() .subclass(Object.class) .name("com.valsong.dynamicdto.ListArrayContainer") .defineProperty("listArray", listArrayField); DynamicType.Unloaded
dynamicType = dynamicBuilder.make(); saveAndLoad(dynamicType); } /** * 构建 *

* package com.valsong.dynamicdto; *

* import java.util.LinkedHashMap; * import java.util.Map; *

* public class WildcardTypeContainer { * private Map

[] map; *

* public void setMap(Map

[] var1) { * this.map = var1; * } *

* public Map

[] getMap() { * return this.map; * } *

* public WildContainer() { * } * } * * @throws ClassNotFoundException */ @Test public void makeWildcardType() throws ClassNotFoundException { Class

rawType = Map.class; List
type1ArgumentsDefinitions = new ArrayList<>(2); // ? extends Number type1ArgumentsDefinitions.add(TypeDescription.Generic.OfWildcardType.Latent .boundedAbove(new TypeDescription.ForLoadedType(Number.class).asGenericType(), AnnotationSource.Empty.INSTANCE)); // ? super LinkedHashMap type1ArgumentsDefinitions.add(TypeDescription.Generic.OfWildcardType.Latent .boundedBelow(new TypeDescription.ForLoadedType(LinkedHashMap.class).asGenericType(), AnnotationSource.Empty.INSTANCE)); //ownerType泛型 TypeDescription.Generic ownerTypeGeneric = Optional.ofNullable(rawType.getDeclaringClass()) .map(TypeDefinition.Sort::describe) .orElse(null); //Map
TypeDefinition mapField = TypeDescription.Generic.Builder.parameterizedType( //TypeDescription.ForLoadedType.of(rawType) //为了解决版本冲突将bytebuddy版本改成了1.7.11 new TypeDescription.ForLoadedType(rawType) , ownerTypeGeneric, type1ArgumentsDefinitions) .asArray() .build(); DynamicType.Builder dynamicBuilder = new ByteBuddy() .subclass(Object.class) .name("com.valsong.dynamicdto.WildcardTypeContainer") .defineProperty("map", mapField); DynamicType.Unloaded
dynamicType = dynamicBuilder.make(); saveAndLoad(dynamicType); } /** * 构建 *

* import java.util.List; *

* public class Container

{ * private List
[] ts; * private K k; *

* public void setTs(List

[] var1) { * this.ts = var1; * } *

* public List

[] getTs() { * return this.ts; * } *

* public void setK(K var1) { * this.k = var1; * } *

* public K getK() { * return this.k; * } *

* public Container() { * } * } */ @Test public void makeTypeVariable() { Class

rawType = List.class; //T TypeDefinition tGeneric = TypeDescription.Generic.Builder.typeVariable("T").build(); List
typeArgumentsDefinitions = new ArrayList<>(2); typeArgumentsDefinitions.add(tGeneric); //ownerType泛型 TypeDescription.Generic ownerTypeGeneric = Optional.ofNullable(rawType.getDeclaringClass()) .map(TypeDefinition.Sort::describe) .orElse(null); //List
TypeDefinition tsField = TypeDescription.Generic.Builder.parameterizedType( //TypeDescription.ForLoadedType.of(rawType) //为了解决版本冲突将bytebuddy版本改成了1.7.11 new TypeDescription.ForLoadedType(rawType) , ownerTypeGeneric, typeArgumentsDefinitions) .asArray() .build(); //K TypeDefinition kGeneric = TypeDescription.Generic.Builder.typeVariable("K").build(); DynamicType.Builder dynamicBuilder = new ByteBuddy() .subclass(Object.class) .name("com.valsong.dynamicdto.Container") .typeVariable("T") .typeVariable("K", Number.class) .defineProperty("ts", tsField) .defineProperty("k", kGeneric); DynamicType.Unloaded
dynamicType = dynamicBuilder.make(); saveAndLoad(dynamicType); } /** * 构建 *

* package com.valsong.dynamicdto; *

* import java.util.LinkedHashMap; * import java.util.List; * import java.util.Map; *

* public class GenericCollectionContainer { * private List

> list; * private Map
>[] mapArray; *

* public void setList(List

> var1) { * this.list = var1; * } *

* public List

> getList() { * return this.list; * } *

* public void setMapArray(Map

>[] var1) { * this.mapArray = var1; * } *

* public Map

>[] getMapArray() { * return this.mapArray; * } *

* public GenericCollectionContainer() { * } * } * * @throws ClassNotFoundException */ @Test public void makeGenericDtoUseType() throws ClassNotFoundException { Type listType = new TypeReference

>>() { }.getType(); Type mapArrayType = new TypeReference
>[]>() { }.getType(); DynamicType.Builder dynamicBuilder = new ByteBuddy() .subclass(Object.class) .name("com.valsong.dynamicdto.GenericCollectionContainer") .defineProperty("list", listType) .defineProperty("mapArray", mapArrayType); DynamicType.Unloaded
dynamicType = dynamicBuilder.make(); saveAndLoad(dynamicType); } /** * package com.valsong.dynamicdto; *

* import com.valsong.bytebuddy.ByteBuddyTest.DataConverterExecutor; * import java.lang.reflect.Type; *

* public class DataConverter { * public static String toJson(Object obj) { * return DataConverterExecutor.toJson(var0); * } *

* public static Object fromJson(String json, Type type) { * return DataConverterExecutor.fromJson(var0, var1); * } *

* public DataConverter() { * } * } */ @Test public void makeMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { DynamicType.Builder dynamicBuilder = new ByteBuddy() .subclass(Object.class) .name("com.valsong.dynamicdto.DataConverter"); dynamicBuilder = dynamicBuilder.defineMethod("toJson", String.class, Modifier.PUBLIC + Modifier.STATIC) .withParameter(Object.class, "obj") .intercept(MethodDelegation.to(DataConverterExecutor.class)) .defineMethod("fromJson", Object.class, Modifier.PUBLIC + Modifier.STATIC) .withParameter(String.class, "json") .withParameter(Type.class, "type") .intercept(MethodDelegation.to(DataConverterExecutor.class)); DynamicType.Unloaded

dynamicType = dynamicBuilder.make(); Class
clazz = saveAndLoad(dynamicType); User user = User.newBuilder() .name("val") .age(27) .height(172.0) .email("valsong@163.com") .build(); Method toJsonMethod = clazz.getMethod("toJson", Object.class); String json = (String) toJsonMethod.invoke(null, user); System.out.println(json); Assertions.assertNotNull(json); Method fromJsonMethod = clazz.getMethod("fromJson", String.class, Type.class); User user2 = (User) fromJsonMethod.invoke(null, json, User.class); Assertions.assertEquals(user, user2); } /** * 保存到本地目录,并且加载到类加载器中 * * @param dynamicType */ private Class
saveAndLoad(DynamicType.Unloaded
dynamicType) { //写入到本地目录 try { dynamicType.saveIn(new File("target/classes")); } catch (IOException e) { e.printStackTrace(); } return dynamicType.load(Thread.currentThread().getContextClassLoader(), ClassLoadingStrategy.Default.INJECTION).getLoaded(); } public static class DataConverterExecutor { public static String toJson(Object obj) { return JSON.toJSONString(obj); } public static
T fromJson(@Argument(0) String json, @Argument(1) Type type) { return JSON.parseObject(json, type); } }}

上述测试用例用到的DTO和自定义注解

package com.valsong.dto;import java.util.Objects;public class User {    private String name;    private Integer age;    private Double height;    private String email;    public User() {    }    private User(Builder builder) {        setName(builder.name);        setAge(builder.age);        setHeight(builder.height);        setEmail(builder.email);    }    public static Builder newBuilder() {        return new Builder();    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public Integer getAge() {        return age;    }    public void setAge(Integer age) {        this.age = age;    }    public Double getHeight() {        return height;    }    public void setHeight(Double height) {        this.height = height;    }    public String getEmail() {        return email;    }    public void setEmail(String email) {        this.email = email;    }    public static final class Builder {        private String name;        private Integer age;        private Double height;        private String email;        private Builder() {        }        public Builder name(String val) {            name = val;            return this;        }        public Builder age(Integer val) {            age = val;            return this;        }        public Builder height(Double val) {            height = val;            return this;        }        public Builder email(String val) {            email = val;            return this;        }        public User build() {            return new User(this);        }    }    @Override    public String toString() {        return "User{" +                "name='" + name + '\'' +                ", age=" + age +                ", height=" + height +                ", email='" + email + '\'' +                '}';    }    @Override    public boolean equals(Object o) {        if (this == o) return true;        if (o == null || getClass() != o.getClass()) return false;        User user = (User) o;        return Objects.equals(name, user.name) &&                Objects.equals(age, user.age) &&                Objects.equals(height, user.height) &&                Objects.equals(email, user.email);    }    @Override    public int hashCode() {        return Objects.hash(name, age, height, email);    }}
package com.valsong.bytebuddy;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE,ElementType.TYPE_PARAMETER,ElementType.TYPE_USE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface MyAnnotation {    String value() default "";    String name() default "";    boolean required() default false;}

转载于:https://my.oschina.net/valsong/blog/2988403

你可能感兴趣的文章
PHPStorm + Homestead + Xdebug + Chrome Xdebug Helper 调试配置
查看>>
Java计算这位同学的平均分
查看>>
p2421 荒岛野人
查看>>
js 5
查看>>
【0】如何在电脑中使用多个python版本【python虚拟环境配置】
查看>>
前端css框架SASS使用教程(转)
查看>>
20120627小记
查看>>
语义化的HTML及其目的
查看>>
算法一回首之《括号匹配算法》
查看>>
Permissions 0664 for '/home/root/.ssh/id_rsa' are too open.
查看>>
Fiddler工具的基本功能(转)
查看>>
oracle事务(转)
查看>>
Codeforces Round #329(Div2)
查看>>
虚拟机console基础环境部署——安全加固
查看>>
NewtonSoft对象转json时,把 NULL 转 "" , 过滤 NULL, DateTime 时间类型去除 T
查看>>
数据库索引
查看>>
华为交换机常用配置命令
查看>>
PHPUnit学习02---如何管理TestCase
查看>>
[MySQL] 索引中的b树索引
查看>>
git/github常用指令、入门
查看>>