下面列出了javax.validation.Constraint#javassist.bytecode.ClassFile 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
public void scan(final Object cls) {
final ClassFile classFile = (ClassFile)cls;
AnnotationsAttribute annotations = ((AnnotationsAttribute)classFile.getAttribute(AnnotationsAttribute.visibleTag));
if (annotations != null) {
boolean isAnnotated = false;
for (javassist.bytecode.annotation.Annotation a : annotations.getAnnotations()) {
if (annotationsToScan.contains(a.getTypeName())) {
isAnnotated = true;
}
}
if (isAnnotated) {
List<AnnotationDescriptor> classAnnotations = getAnnotationDescriptors(annotations);
List<FieldInfo> classFields = classFile.getFields();
List<FieldDescriptor> fieldDescriptors = new ArrayList<>(classFields.size());
for (FieldInfo field : classFields) {
String fieldName = field.getName();
AnnotationsAttribute fieldAnnotations = ((AnnotationsAttribute) field.getAttribute(AnnotationsAttribute.visibleTag));
fieldDescriptors.add(new FieldDescriptor(fieldName, field.getDescriptor(), getAnnotationDescriptors(fieldAnnotations)));
}
functions.add(new AnnotatedClassDescriptor(classFile.getName(), classAnnotations, fieldDescriptors));
}
}
}
BulkAccessor create() {
final Method[] getters = new Method[getterNames.length];
final Method[] setters = new Method[setterNames.length];
findAccessors( targetBean, getterNames, setterNames, types, getters, setters );
final Class beanClass;
try {
final ClassFile classfile = make( getters, setters );
final ClassLoader loader = this.getClassLoader();
if ( writeDirectory != null ) {
FactoryHelper.writeFile( classfile, writeDirectory );
}
beanClass = FactoryHelper.toClass( classfile, loader, getDomain() );
return (BulkAccessor) this.newInstance( beanClass );
}
catch ( Exception e ) {
throw new BulkAccessorException( e.getMessage(), e );
}
}
@Override
public void handleEntry(ArchiveEntry entry, ArchiveContext context) {
// Ultimately we'd like to leverage Jandex here as long term we want to move to
// using Jandex for annotation processing. But even then, Jandex atm does not have
// any facility for passing a stream and conditionally indexing it into an Index or
// returning existing ClassInfo objects.
//
// So not sure we can ever not do this unconditional input stream read :(
final ClassFile classFile = toClassFile( entry );
final ClassDescriptor classDescriptor = toClassDescriptor( classFile, entry );
if ( classDescriptor.getCategorization() == ClassDescriptor.Categorization.OTHER ) {
return;
}
resultCollector.handleClass( classDescriptor, context.isRootUrl() );
}
private ClassDescriptor toClassDescriptor(ClassFile classFile, ArchiveEntry entry) {
ClassDescriptor.Categorization categorization = ClassDescriptor.Categorization.OTHER;;
final AnnotationsAttribute visibleAnnotations = (AnnotationsAttribute) classFile.getAttribute( AnnotationsAttribute.visibleTag );
if ( visibleAnnotations != null ) {
if ( visibleAnnotations.getAnnotation( Entity.class.getName() ) != null
|| visibleAnnotations.getAnnotation( MappedSuperclass.class.getName() ) != null
|| visibleAnnotations.getAnnotation( Embeddable.class.getName() ) != null ) {
categorization = ClassDescriptor.Categorization.MODEL;
}
else if ( visibleAnnotations.getAnnotation( Converter.class.getName() ) != null ) {
categorization = ClassDescriptor.Categorization.CONVERTER;
}
}
return new ClassDescriptorImpl( classFile.getName(), categorization, entry.getStreamAccess() );
}
/**
* Declares a constructor that takes no parameter.
*
* @param classfile
* @throws CannotCompileException
*/
private void addDefaultConstructor(ClassFile classfile) throws CannotCompileException {
ConstPool cp = classfile.getConstPool();
String cons_desc = "()V";
MethodInfo mi = new MethodInfo( cp, MethodInfo.nameInit, cons_desc );
Bytecode code = new Bytecode( cp, 0, 1 );
// aload_0
code.addAload( 0 );
// invokespecial
code.addInvokespecial( BulkAccessor.class.getName(), MethodInfo.nameInit, cons_desc );
// return
code.addOpcode( Opcode.RETURN );
mi.setCodeAttribute( code.toCodeAttribute() );
mi.setAccessFlags( AccessFlag.PUBLIC );
classfile.addMethod( mi );
}
@Test
public void givenTableOfInstructions_whenAddNewInstruction_thenShouldConstructProperSequence() throws NotFoundException, BadBytecode, CannotCompileException, IllegalAccessException, InstantiationException {
// given
ClassFile cf = ClassPool.getDefault().get("com.baeldung.javasisst.ThreeDimensionalPoint").getClassFile();
// when
FieldInfo f = new FieldInfo(cf.getConstPool(), "id", "I");
f.setAccessFlags(AccessFlag.PUBLIC);
cf.addField(f);
ClassPool classPool = ClassPool.getDefault();
Field[] fields = classPool.makeClass(cf).toClass().getFields();
List<String> fieldsList = Stream.of(fields).map(Field::getName).collect(Collectors.toList());
assertTrue(fieldsList.contains("id"));
}
private void addSetFieldHandlerMethod(ClassFile classfile)
throws CannotCompileException {
ConstPool cp = classfile.getConstPool();
int this_class_index = cp.getThisClassInfo();
MethodInfo minfo = new MethodInfo(cp, SETFIELDHANDLER_METHOD_NAME,
SETFIELDHANDLER_METHOD_DESCRIPTOR);
/* local variables | this | callback | */
Bytecode code = new Bytecode(cp, 3, 3);
// aload_0 // load this
code.addAload(0);
// aload_1 // load callback
code.addAload(1);
// putfield // put field "$JAVASSIST_CALLBACK" defined already
code.addOpcode(Opcode.PUTFIELD);
int field_index = cp.addFieldrefInfo(this_class_index,
HANDLER_FIELD_NAME, HANDLER_FIELD_DESCRIPTOR);
code.addIndex(field_index);
// return
code.addOpcode(Opcode.RETURN);
minfo.setCodeAttribute(code.toCodeAttribute());
minfo.setAccessFlags(AccessFlag.PUBLIC);
classfile.addMethod(minfo);
}
private void addReadWriteMethods(ClassFile classfile)
throws CannotCompileException {
List fields = classfile.getFields();
for (Iterator field_iter = fields.iterator(); field_iter.hasNext();) {
FieldInfo finfo = (FieldInfo) field_iter.next();
if ((finfo.getAccessFlags() & AccessFlag.STATIC) == 0
&& (!finfo.getName().equals(HANDLER_FIELD_NAME))) {
// case of non-static field
if (filter.handleRead(finfo.getDescriptor(), finfo
.getName())) {
addReadMethod(classfile, finfo);
readableFields.put(finfo.getName(), finfo
.getDescriptor());
}
if (filter.handleWrite(finfo.getDescriptor(), finfo
.getName())) {
addWriteMethod(classfile, finfo);
writableFields.put(finfo.getName(), finfo
.getDescriptor());
}
}
}
}
private int transformInvokevirtualsIntoGetfields(ClassFile classfile,
CodeIterator iter, int pos) {
ConstPool cp = classfile.getConstPool();
int c = iter.byteAt(pos);
if (c != Opcode.GETFIELD) {
return pos;
}
int index = iter.u16bitAt(pos + 1);
String fieldName = cp.getFieldrefName(index);
String className = cp.getFieldrefClassName(index);
if ((!classfile.getName().equals(className))
|| (!readableFields.containsKey(fieldName))) {
return pos;
}
String desc = "()" + (String) readableFields.get(fieldName);
int read_method_index = cp.addMethodrefInfo(cp.getThisClassInfo(),
EACH_READ_METHOD_PREFIX + fieldName, desc);
iter.writeByte(Opcode.INVOKEVIRTUAL, pos);
iter.write16bit(read_method_index, pos + 1);
return pos;
}
@Test
public void givenLoadedClass_whenAddConstructorToClass_shouldCreateClassWithConstructor() throws NotFoundException, CannotCompileException, BadBytecode {
// given
ClassFile cf = ClassPool.getDefault().get("com.baeldung.javasisst.Point").getClassFile();
Bytecode code = new Bytecode(cf.getConstPool());
code.addAload(0);
code.addInvokespecial("java/lang/Object", MethodInfo.nameInit, "()V");
code.addReturn(null);
// when
MethodInfo minfo = new MethodInfo(cf.getConstPool(), MethodInfo.nameInit, "()V");
minfo.setCodeAttribute(code.toCodeAttribute());
cf.addMethod(minfo);
// then
CodeIterator ci = code.toCodeAttribute().iterator();
List<String> operations = new LinkedList<>();
while (ci.hasNext()) {
int index = ci.next();
int op = ci.byteAt(index);
operations.add(Mnemonic.OPCODE[op]);
}
assertEquals(operations, Arrays.asList("aload_0", "invokespecial", "return"));
}
@Override
public Collection<Method> select(AnnotationsScannerProcess process, AnnotationScannerStore store) {
Set<String> selectedClasses = new HashSet<>();
MetadataAdapter<ClassFile, FieldInfo, MethodInfo> adapter = process.getMetadataAdapter();
for (ClassFile cachedClassFile : store.getCachedClassFiles()) {
for (MethodInfo method : adapter.getMethods(cachedClassFile)) {
for (String annotationName : adapter.getMethodAnnotationNames(method)) {
if (annotationType.getName().equals(annotationName)) {
selectedClasses.add(adapter.getMethodFullKey(cachedClassFile, method));
}
}
}
}
return AnnotationsScannerUtils.forMethods(process, selectedClasses);
}
public CtMethod addToClass(CtClass declaringClass) throws CannotCompileException {
if (this.returnType == null) {
this.returnType = declaringClass;
}
CtMethod ctMethod = CtNewMethod.make(this.modifier, this.returnType, this.name, this.parameters, this.exceptions, this.body, declaringClass);
ctMethod.setModifiers(this.modifier);
declaringClass.addMethod(ctMethod);
for (String annotation : annotations) {
ClassFile classFile = declaringClass.getClassFile();
ConstPool constPool = classFile.getConstPool();
AnnotationsAttribute attr = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
Annotation annot = new Annotation(annotation, constPool);
attr.setAnnotation(annot);
ctMethod.getMethodInfo().addAttribute(attr);
}
return ctMethod;
}
@Test
public void givenJavasisstAPI_whenConstructClass_thenGenerateAClassFile() throws CannotCompileException, IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {
// given
String classNameWithPackage = "com.baeldung.JavassistGeneratedClass";
ClassFile cf = new ClassFile(false, classNameWithPackage, null);
cf.setInterfaces(new String[] { "java.lang.Cloneable" });
FieldInfo f = new FieldInfo(cf.getConstPool(), "id", "I");
f.setAccessFlags(AccessFlag.PUBLIC);
cf.addField(f);
// when
String className = "JavassistGeneratedClass.class";
cf.write(new DataOutputStream(new FileOutputStream(className)));
// then
ClassPool classPool = ClassPool.getDefault();
Field[] fields = classPool.makeClass(cf).toClass().getFields();
assertEquals(fields[0].getName(), "id");
String classContent = new String(Files.readAllBytes(Paths.get(className)));
assertTrue(classContent.contains("java/lang/Cloneable"));
}
@Test
public void givenJavaClass_whenLoadAtByJavassist_thenTraversWholeClass() throws NotFoundException, CannotCompileException, BadBytecode {
// given
ClassPool cp = ClassPool.getDefault();
ClassFile cf = cp.get("com.baeldung.javasisst.Point").getClassFile();
MethodInfo minfo = cf.getMethod("move");
CodeAttribute ca = minfo.getCodeAttribute();
CodeIterator ci = ca.iterator();
// when
List<String> operations = new LinkedList<>();
while (ci.hasNext()) {
int index = ci.next();
int op = ci.byteAt(index);
operations.add(Mnemonic.OPCODE[op]);
}
// then
assertEquals(operations, Arrays.asList("aload_0", "iload_1", "putfield", "aload_0", "iload_2", "putfield", "return"));
}
@Override
public void scan(final Object cls) {
final ClassFile classFile = (ClassFile)cls;
String className = classFile.getName();
String superclass = classFile.getSuperclass();
boolean isAbstract = (classFile.getAccessFlags() & (AccessFlag.INTERFACE | AccessFlag.ABSTRACT)) != 0;
ChildClassDescriptor scannedClass = new ChildClassDescriptor(className, isAbstract);
if (!superclass.equals(Object.class.getName())) {
children.put(superclass, scannedClass);
}
for (String anInterface : classFile.getInterfaces()) {
children.put(anInterface, scannedClass);
}
}
protected String getReplaceStatement(
CtConstructor constructor,
boolean initializer,
String statement) {
if (!initializer) {
statement = replaceAnnotationStatement(constructor, statement);
}
MethodInfo methodInfo = constructor.getMethodInfo();
int line = methodInfo.getLineNumber(0);
String name = initializer ? "<clinit>" : "<init>";
String className = constructor.getDeclaringClass().getName();
ClassFile classFile2 = constructor.getDeclaringClass().getClassFile2();
String fileName = classFile2 == null ? null : classFile2.getSourceFile();
return getReplaceStatement(statement, line, name, className, fileName);
}
protected String getReplaceStatement(CtMethod method, String statement) {
statement = replaceAnnotationStatement(method, statement);
MethodInfo methodInfo = method.getMethodInfo();
int line = methodInfo.getLineNumber(0);
String name = method.getName();
String className = method.getDeclaringClass().getName();
ClassFile classFile2 = method.getDeclaringClass().getClassFile2();
String fileName = classFile2 == null ? null : classFile2.getSourceFile();
return getReplaceStatement(statement, line, name, className, fileName);
}
private ClassFile getClassFile(JarFile jarFile, ZipEntry zipEntry) {
if (!zipEntry.isDirectory()) {
try (InputStream inputStream = jarFile.getInputStream(zipEntry)) {
DataInputStream dataInputStream = new DataInputStream(new BufferedInputStream(inputStream));
return new ClassFile(dataInputStream);
} catch (IOException e) {
// Some zip entries are not class files
return null;
}
}
return null;
}
public Set<JInterface> getSubInterfaces() {
Set<JInterface> retVal = new HashSet<JInterface>();
List<? extends ClassFile> classes = getResolver().getClassFileResolver().resolveAll(null, CLASSPATH_PROJECTOR, new JTypeSubTypeOfFilter(this.getActualClass()), new JElementTypeFilter(JInterface.class));
for (ClassFile classFile : classes) {
retVal.add(JInterface.getJInterface(classFile, getResolver()));
}
return retVal;
}
/**
* Adds one additional member to the class: A boolean to indicate that the class has been instrumented
* (so that later processes and threads do not need to do it again).
*
* @throws javassist.CannotCompileException if any.
* @throws java.io.IOException if any.
*/
public synchronized void finalizeInstrumentation() throws CannotCompileException, IOException {
// Add member to indicate that the class has been instrumented
if(!this.isInstrumented()) {
this.addBooleanMember("VUL_CLS_INS", true, true);
this.isInstrumented = new Boolean(true);
}
// this.bytes = this.c.toBytecode();
// Alternatively, create the byte array from the classfile
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
final DataOutputStream dos = new DataOutputStream(bos);
final ClassFile cf = c.getClassFile();
// Set major and minor version of the new class file (max. JAVA 7), preferably from the original class file (as read in the constructor)
// Todo: Make max. version configurable
cf.setMajorVersion(Math.min(this.major, ClassFile.JAVA_7));
cf.setMinorVersion(this.minor);
cf.write(dos);
dos.flush();
this.bytes = bos.toByteArray();
this.c.detach(); // Removes the CtClass from the ClassPool
if(this.writeCodeToTmp) {
Path p = null;
try {
p = Paths.get(VulasConfiguration.getGlobal().getTmpDir().toString(), this.javaId.getJavaPackageId().getQualifiedName().replace('.','/'), this.javaId.getName().replace('<', '_').replace('>','_') + ".class");
FileUtil.createDirectory(p.getParent());
FileUtil.writeToFile(p.toFile(), this.bytes);
} catch(IOException e) {
ClassVisitor.getLog().warn("Cannot write bytecode of " + this.javaId+ " to file [" + p + "]: " + e.getMessage());
} catch(InvalidPathException ipe) {
ClassVisitor.getLog().warn("Cannot write bytecode of " + this.javaId+ " to file [" + p + "]: " + ipe.getMessage());
}
}
}
private ClassFile make(Method[] getters, Method[] setters) throws CannotCompileException {
String className = targetBean.getName();
// set the name of bulk accessor.
className = className + "_$$_bulkaccess_" + counter++;
if ( className.startsWith( "java." ) ) {
className = PACKAGE_NAME_PREFIX + className;
}
final ClassFile classfile = new ClassFile( false, className, BULKACESSOR_CLASS_NAME );
classfile.setAccessFlags( AccessFlag.PUBLIC );
addDefaultConstructor( classfile );
addGetter( classfile, getters );
addSetter( classfile, setters );
return classfile;
}
@Override
public void scan(final Object cls) {
final ClassFile classFile = (ClassFile)cls;
String className = classFile.getName();
String superclass = classFile.getSuperclass();
boolean isAbstract = (classFile.getAccessFlags() & (AccessFlag.INTERFACE | AccessFlag.ABSTRACT)) != 0;
ChildClassDescriptor scannedClass = new ChildClassDescriptor(className, isAbstract);
if (!superclass.equals(Object.class.getName())) {
children.put(superclass, scannedClass);
}
for (String anInterface : classFile.getInterfaces()) {
children.put(anInterface, scannedClass);
}
}
@Override
public void scan(final Object cls) {
final ClassFile classFile = (ClassFile)cls;
AnnotationsAttribute annotations = ((AnnotationsAttribute)classFile.getAttribute(AnnotationsAttribute.visibleTag));
if (annotations != null) {
boolean isAnnotated = false;
for (javassist.bytecode.annotation.Annotation a : annotations.getAnnotations()) {
if (annotationsToScan.contains(a.getTypeName())) {
isAnnotated = true;
}
}
if (isAnnotated) {
List<AnnotationDescriptor> classAnnotations = getAnnotationDescriptors(annotations);
@SuppressWarnings("unchecked")
List<FieldInfo> classFields = classFile.getFields();
List<FieldDescriptor> fieldDescriptors = new ArrayList<>(classFields.size());
for (FieldInfo field : classFields) {
String fieldName = field.getName();
AnnotationsAttribute fieldAnnotations = ((AnnotationsAttribute)field.getAttribute(AnnotationsAttribute.visibleTag));
final List<AnnotationDescriptor> annotationDescriptors =
(fieldAnnotations != null) ? getAnnotationDescriptors(fieldAnnotations) : Collections.<AnnotationDescriptor>emptyList();
fieldDescriptors.add(new FieldDescriptor(fieldName, field.getDescriptor(), annotationDescriptors));
}
functions.add(new AnnotatedClassDescriptor(classFile.getName(), classAnnotations, fieldDescriptors));
}
}
}
/**
* 对mapper进行增强,生成新的mapper,并主动加载新mapper类到classloader
*
* @param mapperClassName
*/
public static void enhanceMapperClass(String mapperClassName) throws Exception {
Class originClass = Class.forName(mapperClassName);
Method[] originMethods = originClass.getDeclaredMethods();
CtClass cc = pool.get(mapperClassName);
for (CtMethod ctMethod : cc.getDeclaredMethods()) {
CtClass enhanceClass = pool.makeInterface(mapperClassName + "Sharding" + ctMethod.getName());
for (long i = 0L; i < 512; i++) {
CtMethod newMethod = new CtMethod(ctMethod.getReturnType(), ctMethod.getName() + ShardingCaculator.getNumberWithZeroSuffix(i), ctMethod.getParameterTypes(), enhanceClass);
Method method = getOriginMethod(newMethod, originMethods);
if(method.getParameterAnnotations()[0].length > 0) {
ClassFile ccFile = enhanceClass.getClassFile();
ConstPool constPool = ccFile.getConstPool();
//拷贝注解信息和注解内容,以支持mybatis mapper类的动态绑定
newMethod.getMethodInfo().addAttribute(MapperAnnotationEnhancer.duplicateParameterAnnotationsAttribute(constPool, method));
}
enhanceClass.addMethod(newMethod);
}
Class<?> loadThisClass = enhanceClass.toClass();
//2015.09.22后不再输出类到本地
// enhanceClass.writeFile(".");
}
}
private static void scanFile(Collection<String> classes, Pattern regex,
Class<? extends Annotation>[] annotated, Predicate<InputStream> bytecodeFilter, String relName,
File file, ZipFile zip, ZipEntry entry, AtomicInteger searched) {
Log.trace("scanned file", "file", relName);
if (relName.endsWith(".class")) {
searched.incrementAndGet();
String clsName = Str.sub(relName, 0, -6).replace('/', '.').replace('\\', '.');
if (U.isEmpty(regex) || regex.matcher(clsName).matches()) {
try {
InputStream input = file != null ? new FileInputStream(file) : zip.getInputStream(entry);
boolean include;
if (U.isEmpty(annotated)) {
include = true;
} else {
ClassFile classFile = new ClassFile(new DataInputStream(input));
include = isAnnotated(classFile, annotated);
}
if (include && bytecodeFilter != null) {
include = Lmbd.eval(bytecodeFilter, input);
}
if (include) {
classes.add(clsName);
}
} catch (Throwable e) {
Log.debug("Error while loading class", "name", clsName, "error", e);
}
}
}
}
private ClassFile make(Method[] getters, Method[] setters) throws CannotCompileException {
String className = targetBean.getName();
// set the name of bulk accessor.
className = className + "_$$_bulkaccess_" + counter++;
if ( className.startsWith( "java." ) ) {
className = "org.javassist.tmp." + className;
}
ClassFile classfile = new ClassFile( false, className, BULKACESSOR_CLASS_NAME );
classfile.setAccessFlags( AccessFlag.PUBLIC );
addDefaultConstructor( classfile );
addGetter( classfile, getters );
addSetter( classfile, setters );
return classfile;
}
public Set<JClass> getClasses() throws ClasspathAccessException {
Set<JClass> retVal = new HashSet<JClass>();
List<? extends ClassFile> classes = getResolver().getClassFileResolver().resolveAll(null, CLASSPATH_PROJECTOR, new PackageFileFilter(getName(), false), new PackagePrefixFilter(this), new JElementTypeFilter(JClass.class));
for (ClassFile classFile : classes) {
if ((classFile.getSuperclass() != null) &&
(!classFile.isInterface() && (!classFile.getSuperclass().equals("java.lang.Enum"))
&& (classFile.getInnerAccessFlags() == -1))) {
retVal.add(JClass.getJClass(classFile, getResolver()));
}
}
return retVal;
}
private boolean alreadyInstrumented(ClassFile classfile) {
String[] intfs = classfile.getInterfaces();
for ( int i = 0; i < intfs.length; i++ ) {
if ( FieldHandled.class.getName().equals( intfs[i] ) ) {
return true;
}
}
return false;
}
public void transform(File file) throws Exception {
DataInputStream in = new DataInputStream(new FileInputStream(file));
ClassFile classfile = new ClassFile(in);
transform(classfile);
DataOutputStream out = new DataOutputStream(new FileOutputStream(file));
try {
classfile.write(out);
} finally {
out.close();
}
}
public void transform(ClassFile classfile) throws Exception {
if (classfile.isInterface()) {
return;
}
try {
addFieldHandlerField(classfile);
addGetFieldHandlerMethod(classfile);
addSetFieldHandlerMethod(classfile);
addFieldHandledInterface(classfile);
addReadWriteMethods(classfile);
transformInvokevirtualsIntoPutAndGetfields(classfile);
} catch (CannotCompileException e) {
throw new RuntimeException(e.getMessage(), e);
}
}