2013-05-29 144 views
2

我正在嘗試編寫代碼來註釋類中的字段,以便從配置文件中設置該字段的值。這實際上與Spring框架所具有的@Value屬性相同,但出於我不會涉及的原因,我沒有使用spring框架。通過註釋的Java字段注入

我正在開發的項目是一個使用Jersey框架的Web應用程序。我對所有的前期信息道歉,但爲了完整起見,這裏是什麼,我有一個基本設置:

這是主應用程序類:

package com.ttrr.myservice; 

import com.ttrr.myservice.controllers.MyController; 

import javax.ws.rs.ApplicationPath; 
import javax.ws.rs.core.Application; 
import java.util.HashSet; 
import java.util.Set; 

@ApplicationPath("/") 
public class MyApplication extends Application { 
    @Override 
    public Set<Class<?>> getClasses() { 
     final Set<Class<?>> classes = new HashSet<Class<?>>(); 
     // register root resources    
     classes.add(MyController.class); 

     return classes; 
    } 
} 

這是myController的類,我想說明在工作:

package com.ttrr.myservice.controllers; 

import com.ttrr.myservice.annotations.Property; 

import javax.servlet.ServletContext; 
import javax.ws.rs.GET; 
import javax.ws.rs.Path; 
import javax.ws.rs.Produces; 
import javax.ws.rs.core.Context; 

@Path("test") 
public class MyController { 

    @Property("my.value.from.config") 
    private String myValue; 

    @GET 
    @Produces("text/html") 
    @Path("/testPage") 
    public String testPage(@Context ServletContext context) {   

     return "<p>" + myValue + "</p>"; 
    } 
} 

我的註釋界面是非常簡單的:

package com.ttrr.myservice.annotations; 

import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 

@Target(ElementType.FIELD) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface Property { 
    String value() default ""; 
} 

而且我有一個註解解析器類:

package com.ttrr.myservice.annotations; 

import java.io.IOException; 
import java.lang.reflect.Field; 
import java.util.Properties; 

public class PropertyParser { 

    public static Properties properties; 

    static { 
     properties = new Properties(); 
     try { 
      Property.class.getClassLoader(); 

      Properties defaults = new Properties(); 
      defaults.load(Property.class.getClassLoader().getResourceAsStream("application.properties")); 

      for(Object key : defaults.keySet()) { 
       properties.put(key, defaults.get(key)); 
      } 

     } catch (IOException e) { 
      //in this case do nothing, properties will simply be empty 
     } 
    } 

    public void parse(Class<?> clazz) throws Exception { 

     Field[] fields = clazz.getDeclaredFields(); 

     for (Field field : fields) { 
      if (field.isAnnotationPresent(Property.class)) { 
       Property property = field.getAnnotation(Property.class); 
       String value = property.value(); 

       if (!"".equals(value)) { 
        field.set(clazz, properties.getProperty(value)); 
       } 
      } 
     } 
    } 
} 

在哪裏我真的很努力的把他們放在一起,並得到從我application.properties值文件到類myController的一個實例。

感謝您花時間閱讀所有內容!任何幫助將不勝感激。

+0

? – Guillaume

+0

最初,我在MyApplication.getClasses()方法中調用了parse(),但它無法適當地設置值,因爲在那時它只有類而不是一個將值設置爲(至少,我認爲這是問題)。 parse()中的內容爲:field.set(clazz,properties.getProperty(value));是問題。 – wbj

+0

@wbj您調用的方式[Field#set](http://docs.oracle.com/javase/6/docs/api/java/lang/reflect/Field.html#set%28java.lang.Object, %20java.lang.Object%29)只有當字段爲'static'時,纔會成功設置該值,在這種情況下,obj參數'clazz'已過時,否則可能爲'null'(如果該字段不是靜態),你最終會得到一個'java.lang.IllegalArgumentException',除非你傳遞一個實例爲'obj' – A4L

回答

3

您嘗試設置值的方式不正確,因爲您需要實例來設置值。

field.set(clazz, properties.getProperty(value)); 

應該是:

field.set(instance, properties.getProperty(value)); 

而且不應該將參數添加到您的解析方法:你在哪裏打電話給你解析(...)方法

public void parse(Class<?> clazz, Object instance) throws Exception { 
+0

好的,謝謝...這肯定是問題的一部分。我現在已經開始工作了。我一共擺脫了類 clazz參數,並且只是通過實例。缺點是我必須將一個構造函數添加到調用parse()方法的MyController類中。我將把這標記爲答案,但我寧願不必爲每個我寫的類添加一個constructer,並顯式調用parse()。謝謝你的幫助! – wbj

+0

此外,我會投你的答案,但我沒有足夠的聲譽:( – wbj

+0

事實上,clazz參數不再是必要的,如果你通過一個實例的方法!我很高興我可以幫助! – Guillaume