Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

InnerClass property interceptor #1767

Open
ammubasha opened this issue Feb 7, 2025 · 0 comments
Open

InnerClass property interceptor #1767

ammubasha opened this issue Feb 7, 2025 · 0 comments

Comments

@ammubasha
Copy link

i have nested DTO say UserDTO contains inner class Address. i have created createproxy for my DTO and innerclass DTO and try to intercept the setter method and modify the value appropriately. my outter class setter is intercepted while inner class setter not getting interceted.
MY DTO:
/************************************************************************************************************************************/
public class UserDTO {
@SiZe(10)
private String username;

private Address address = new Address();



public void setAddress(Address address) {
	this.address = address;
}

public String getUsername() {
    return username;
}

public void setUsername(String username) {
    this.username = username;
}

public Address getAddress() {
    return address;
}

public class Address { // Non-static inner class
    @Size(10)
    private String city;

    @PhoneNumber(length=10) 
    private String phoneNumber;

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }
}

}
/************************************************************************************************/
my ByteBuddyProcessor API:

ublic class ByteBuddyProcessor {

// Set to track processed classes to prevent infinite recursion
private static final Set<Class<?>> processedClasses = new HashSet<>();

public static <T> T createProxy(Class<T> clazz, Object outerInstance) throws Exception {
    // Prevent infinite recursion by checking if the class was already processed
    if (processedClasses.contains(clazz)) {
        return instantiateClass(clazz, outerInstance);
    }
    processedClasses.add(clazz);

    DynamicType.Builder<T> builder = new ByteBuddy().subclass(clazz);

    for (Field field : clazz.getDeclaredFields()) {
        if (field.isAnnotationPresent(Size.class) || field.isAnnotationPresent(PhoneNumber.class)) {
            String setterName = "set" + Character.toUpperCase(field.getName().charAt(0)) + field.getName().substring(1);

            builder = builder.method(named(setterName))
                    .intercept(MethodDelegation.to(new FieldInterceptor(field)));
        } 
        else if(field.getType().isMemberClass()){
        	//inner = inner.innerTypeOf(outer.toTypeDescription()).asMemberType();
           // outer = outer.declaredTypes(inner.toTypeDescription());
        	System.out.println(field.getName());
        	System.out.println(field.toString());


        	
        }
    }

    // Handle constructor for non-static inner classes
   if (clazz.getEnclosingClass() != null) {
	 
        return instantiateClass(clazz, outerInstance);
    }

    return builder.make()
            .load(clazz.getClassLoader())
            .getLoaded()
            .getDeclaredConstructor()
            .newInstance();
}

private static <T> T instantiateClass(Class<T> clazz, Object outerInstance) throws Exception {
    if (clazz.getEnclosingClass() != null) {
        Constructor<T> constructor = clazz.getDeclaredConstructor(clazz.getEnclosingClass());
        return constructor.newInstance(outerInstance);
    }
    return clazz.getDeclaredConstructor().newInstance();
}

public static class FieldInterceptor {
    private final Field field;

    public FieldInterceptor(Field field) {
        this.field = field;
    }
    

    @RuntimeType
    public Object intercept(@This Object obj, @Argument(0) Object value) throws Exception {
        if (value instanceof String) {
            String stringValue = (String) value;

            if (field.isAnnotationPresent(Size.class)) {
                int maxSize = field.getAnnotation(Size.class).value();
                if (stringValue.length() > maxSize) {
                    stringValue = stringValue.substring(0, maxSize);
                }
            }

            if (field.isAnnotationPresent(PhoneNumber.class)) {
                int phoneLength = field.getAnnotation(PhoneNumber.class).length();
                stringValue = stringValue.replaceAll("\\D", ""); // Remove non-digit characters
                if (stringValue.length() > phoneLength) {
                    stringValue = stringValue.substring(0, phoneLength);
                }
            }

            field.setAccessible(true);
            field.set(obj, stringValue);
        }
        return null;
    }
}

}
/***********************************************************************************************************************************/
My Test class:

public class TestByteBuddy {
public static void main(String[] args) throws Exception {

    UserDTO user = ByteBuddyProcessor.createProxy(UserDTO.class, null);
    UserDTO.Address address = ByteBuddyProcessor.createProxy(user.getAddress().getClass(), user);
    user.setAddress(address);

    

    
    user.setUsername("VeryLongUsernameExceedingLimit");

    // Create Address instance properly using the enclosing user instance
   // UserDTO.Address address = ByteBuddyProcessor.createProxy(UserDTO.Address.class, null);
   // Contains extra digits and special characters
    address.setCity("A very long city name that exceeds 15 characters");
    address.setPhoneNumber("98765-43288888993101112");  
    

    System.out.println("Trimmed Username: " + user.getUsername()); // Output: "VeryLongUs"
    System.out.println("Validated Phone Number: " + user.getAddress().getPhoneNumber()); // Output: "9876543210"
    System.out.println("Trimmed City: " + user.getAddress().getCity()); // Output: "A very long ci"
}

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant