2013-05-29 142 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