2013-03-15 11 views
5

kullanarak alanın başlangıç ​​değeri nasıl değiştirilir Gelişmekte olan env'de bazı servisler alay etmeye çalışıyorum. ServiceFactory kodu şunun gibidir:javassist

public class ApiFacadeImpl implements ApiFacade { 
private OneService oneService = null; 
    public OneService getOneService(){ 
     if(oneService==null) {//some initialization steps } 
     return oneService; 
    } 
} 

Bu fabrikanın iyi kodlanmadığını ve tasarlanmadığını biliyorum. Ancak kodunu değiştiremiyorum. benim fikrim bayt kodu değiştirmektir, bu yüzden gibi bir sunucu yeniden tanımlayabilirsiniz:

public class ApiFacadeImpl implements ApiFacade { 
private OneService oneService = new MyMockOneService(); 
    .... 
} 

Benim 1 geçerli: Bu mümkün kullanarak javassist nedir? Ve nasıl? Ben google kullanarak javassist kullanarak alan yeniden başlatmak gibi bir şey bulamıyorum yana

, bunu silerek kendim denedim ve yeniden:

 CtField oneServiceField = cc.getDeclaredField("oneService"); 
    cc.removeField(oneServiceField); 
    CtField f = CtField.make(String.format("private %s %s=new %s();", 
      oneServiceField.getType().getName(), "oneService", 
      mockClass.getCanonicalName()), cc); 
    cc.addField(f); 
    cc.toClass(); 

sonra aldığım istisna:

javassist.CannotCompileException: by java.lang.ClassFormatError: Invalid length 99 in LocalVariableTable in class file com/Test 
at javassist.ClassPool.toClass(ClassPool.java:1051) 
at javassist.ClassPool.toClass(ClassPool.java:994) 
at javassist.ClassPool.toClass(ClassPool.java:952) 
at javassist.CtClass.toClass(CtClass.java:1079) 

Benim ikinci sorum, bu istisna neden? Java sınıfının tanımına hangi adım uymuyor?

public OneService getOneService(){ 
     if(oneService==null) {//some initialization steps } 
     return oneService; 
    } 

çok teşekkür: Ve alanını sildiğinizde alan başvuru silmek için yardımcı javassist yapar.

+0

mockClass.getCanonicalName nedir()? – longhua

+0

Javassist sürümünüz nedir? – longhua

cevap

4

# 1 numaralı soru için evet, ApiFacadeImpl 'un yapıcısını değiştirmek yoluyla bunu başarabilirsiniz. Atama deyimini eklemek için CtConstructor#insertAfter'u kullanmayı unutmayın.

ClassPool pool = ClassPool.getDefault(); 
CtClass factoryClass = pool.getCtClass("ServiceFactory"); 
CtConstructor constructor = factoryClass.getDeclaredConstructor(null); 
String setMockStatement = String.format("service = new %s();", 
     MockServiceImpl.class.getCanonicalName()); 
constructor.insertAfter(setMockStatement); 
factoryClass.toClass(); 
new ServiceFactory().getService().say(); 

Önerilen yolu denedim. Ancak, işe yaramadı. Bazı hata ayıklamalarından sonra, bir alanı kaldırırsak bu alanın başlatma ifadesini kaldırmayacağını buldum. Alanı, beklenen başlatma ifademizle tekrar eklersek, orijinal başlatma ifadesinden önce yürütülür. Yani service alanı ilk olarak MockServiceImpl'a atandı ve daha sonra null'a atandı. Lütfen aşağıdaki deniz kenarındaki böceklere başvurunuz.

javassist-3.14.0-GA - Problm in default initializer of class variables when they are deleted and created using removeField and addField, CtField.make

soru 2., ben bunun neden böyle emin değilim. Senin mahkeme sürümü nedir? Senin mockClass nasıl görünüyor? Aşağıdaki javassist hatayı inceleyebilir misiniz?

Javassist causes java.lang.ClassFormatError: Invalid length 561 in LocalVariableTable in class file

+0

lhuang, cevap için teşekkürler. Aslında mockclass OneServuce'u genişletiyor: MockClass genel sınıfı OneService {// nothing} alanını genişletiyor. Referans bağlantılarını kontrol edeceğim. Javassist-3.11.0.GA btw kullanıyorum. – kingpeter

+0

OneService bir arabirim mi yoksa bir sınıf mı? – longhua

+0

OneService bir sınıftır. – kingpeter

İlgili konular