byte-buddy icon indicating copy to clipboard operation
byte-buddy copied to clipboard

Spring Framework/Hibernate not picking up redefined classes by ByteBuddy

Open productionbug opened this issue 3 years ago • 1 comments

Hi,

I am trying to integrate ByteBuddy with a Spring project that uses spring-data-jpa and hibernate as it's dependency. I am trying to dynamically annotate a field in the data model with the @Transient annotation from javax.persistence.Transient during runtime. The idea is I would like to annotate the field in the data model based on some condition during runtime. Here is how the code looks:

The Data Model


@Entity  
@Getter  
@Setter  
@Builder  
@NoArgsConstructor  
@AllArgsConstructor  
@Table(name = "SOME_TABLE", schema = "someschema")  
public class BubbleTea {  

    @Id  
    @GeneratedValue(strategy = GenerationType.IDENTITY)  
    private Long id;  
  
    private String flavour;  
  
    private String type;  // Add transient dynamically
  
    private BigDecimal price;  
}

Wrapper for @Transient Annotation needed by ByteBuddy


public class TransientImpl implements Transient {  

@Override  
 public Class<? extends Annotation> annotationType() {  
        return Transient.class;  
    }  
}

The Utility Class to Annotate the field with Transient

@Component  
public class BubbleTeaUtility {  
  
    public void addTransient() {  
        ByteBuddyAgent.install();  
  
        new ByteBuddy()  
                .redefine(BubbleTea.class)  
                .field(named("type"))  
                .annotateField(new TransientImpl())  
                .make()  
                .load(BubbleTea.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());  
    }  
}

The Service class using the utility to inject Transient dynamically based on some condition

@RequiredArgsConstructor  
@Service  
@Slf4j  
public class BubbleTeaService {  
  
    private final BubbleTeaRepository bubbleTeaRepository;  
    private final BubbleTeaUtility bubbleTeaUtility;  
  
    public List<BubbleTea> getAllBubbleTeaByFlavour(String flavour) {  
        return bubbleTeaRepository.findByFlavour(flavour);  
    }  
  
    public BubbleTea addBubbleTea(BubbleTea bubbleTea) {  
  
        if (some condition is true) {  
            bubbleTeaUtility.addTransient();  
        }  
  
        return bubbleTeaRepository.save(bubbleTea);  
    }  
}

I have logged out the annotations after the addTransient() method is called and bytebuddy is adding the @Transient annotation successfully. The problem is Hibernate is not picking up the modified classes with the annotation. How do I let Hibernate/Spring pick up the transformed classes with the newly added annotation?

Thank you

productionbug avatar May 09 '22 00:05 productionbug

I assume that those frameworks scan the class path via persisted class files. I am not sure if there is a better way to alter the implicit configuration, but I would guess that code manipulation would need to be applied during build-time for this to work. Byte Buddy offers a build-time plugin for doing this.

raphw avatar May 09 '22 07:05 raphw