/* * Copyright 2001-2008 Geert Bevin (gbevin[remove] at uwyn dot com) * Licensed under the Apache License, Version 2.0 (the "License") * $Id: LazyLoadAccessorsBytecodeTransformer.java 3918 2008-04-14 17:35:35Z gbevin $ */ package com.uwyn.rife.database.querymanagers.generic.instrument; import com.uwyn.rife.asm.ClassReader; import com.uwyn.rife.asm.ClassVisitor; import com.uwyn.rife.asm.ClassWriter; import com.uwyn.rife.database.querymanagers.generic.instrument.LazyLoadClassAdapter; import com.uwyn.rife.database.querymanagers.generic.instrument.LazyLoadMethodCollector; /** * This utility class will modify property accessors of classes that implement * the {@code Constrained} interface and add lazy loading for properties with * manyToOne constraints. * <p> * This is done by modifying the bytecode of the getters by checking if the * value that is returned is {@code null}, and in that case performing the * actual database call to fetch the property value. After that, the property * value is stored in a map that is stored in an added class field so that it * will not be fetched at subsequent calls of the getter. The setter is * modified to remove the values from this map when it is executed, so that * users can still provide their own values for the properties. * <p> * WARNING: this class is not supposed to be used directly, it is made public * since the general RIFE EngineClassLoader has to be able to access it. * * @author Geert Bevin (gbevin[remove] at uwyn dot com) * @version $Revision: 3918 $ * @since 1.6 */ public abstract class LazyLoadAccessorsBytecodeTransformer { /** * The name of the synthentic class field that will be added so that the * instance of the {@code GenericQueryManager} that restored the bean can be * used afterwards to lazily load the relations. */ public final static String GQM_VAR_NAME = "$Rife$Generic$Query$Manager$"; /** * The name of the synthentic class field that will be added so that already * restored lazy relations can be cached. */ public final static String LAZYLOADED_VAR_NAME = "$Rife$Lazy$Loaded$Properties$"; /** * Performs the actual modification of the bean class's bytecode. * @since 1.6 * * @param origBytes the bytes of the bean class that should be modified * @return the modified bytes */ public static byte[] addLazyLoadToBytes(byte[] origBytes) { // obtain all the methods that should be instrumented to add lazy loading ClassReader cr = new ClassReader(origBytes); LazyLoadMethodCollector method_collector = new LazyLoadMethodCollector(); cr.accept(method_collector, ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); ClassVisitor meta_data_adapter = new LazyLoadClassAdapter(method_collector.getMethods(), cw); cr.accept(meta_data_adapter, ClassReader.SKIP_FRAMES); return cw.toByteArray(); } }