我们如何使用java中的反射向现有类添加瞬态?

时间:2013-05-31 18:13:30

标签: java reflection

有没有办法使用java反射API使字段静态或瞬态。

编辑:我有一些Bean已经使用soap api进行序列化并且正在被某些客户端使用,对于某些客户我不想暴露一两个字段。

当然,有很多方法可以做到这一点,而无需更改或添加临时关键字。

只想知道是否可以完成,如果可以,怎么做?

编辑:我不会将其称为API或框架问题,更像是设计缺陷...... 我正在使用apache axis2 for soap

4 个答案:

答案 0 :(得分:5)

没有。这样的事情需要修改类的字节码。 static字段的一个特殊困难是使用与对象字段不同的字节码访问它们。

我没有看到为什么在运行时无法使字段成为transient,至少在理论上,但当前的反射API不允许它。另见:Can a field's transient property/flag be set through reflection in java?

答案 1 :(得分:1)

你不能用反射api做到这一点。我认为有一些字节码操作工具,但在这种情况下,您可以使用Decorator模式。它解决了这个问题,但我觉得它非常难看:

(我从这里省略了通常的样板文件,如接口)

public class StaticDecorator {

    private static Object staticField;
    private Object yourObject;

    public StaticDecorator(Object yourObject) {
        this.yourObject = yourObject;
    }

    public static Object getStaticField() {
        return staticField;
    }

    public static void setStaticField(Object object) {
        staticField = object;
    }

}

我使用Object作为你要包装的类的类型,但当然你可以替换你想要的任何类型。使用这样的方法,您可以使用静态字段“装饰”任何类。

如果您真的,非常必须在运行时想要一个对象中的静态字段,这可以帮助您,但我认为某个地方存在潜伏的设计缺陷。

答案 2 :(得分:1)

您可以将bean包装在另一个bean中,该bean仅公开您希望通过API公开的字段。例如,对于包含字段foobarbaz的内部bean,您不希望公开baz

Lombok Delegation可以使这非常简单,但这是一个使用普通Java的例子。

public class ExposedBean {
    private InternalBean internalBean;
    public ExposedBean(InternalBean internalBean) {
        this.internalBean = internalBean;
    }
    public String getFoo() { return internalBean.getFoo(); }
    public String getBar() { return internalBean.getBar(); }
}

public class InternalBean {
    private String foo;
    private String bar;
    private String baz;
    public String getFoo() { return foo; }
    public String getBar() { return bar; }
    public String getBaz() { return baz; }
}

关于设置修饰符的原始答案

您无法设置修改器。但是,您可以查看它们。

Field myField = /* get a field object */;
if (Modifier.isTransient(myField.getModifiers()) {
    System.out.println("myField is transient.");
}

if (Modifier.isFinal(MyClass.class.getModifiers()) {
    System.out.println("MyClass is final.");
}

有关您尝试解决的问题的更多信息,我们可以建议替代方案。 Member#getModifiers()未声明为final,因此您可以使用装饰器。 (以下代码100%未经测试。)

public class FieldModifierDecorator extends Field {
    protected Field field;
    private int modifiers = -1;

    public static void decorate(Field field) {
        FieldModifierDecorator newInstance = new FieldModifierDecorator();
        newInstance.field = field;
        return newInstance;
    }

    public void overrideModifiers(int modifiers) {
        this.modifiers = modifiers;
    }

    public int getModifiers() {
        if (-1 == modifiers) {
            return field.getModifiers();
        }
        return modifiers;
    }
}

// Example usage
public Field makeFieldAppearTransient(Field field) {
    FieldModifierDecorator decoratedField = FieldModifierDecorator.decorate(field);
    decoratedField.overrideModifiers(field.getModifiers() | Modifier.TRANSIENT);

    // if (Modifier.isTransient(decoratedField.getModifiers())) {
    //     System.out.println("It looks transient, but really isn't.");
    //}

    return decoratedField;
}

答案 3 :(得分:0)

修改类信息或字节码修改绝对是工作的错误工具。您正试图用技术工具解决业务问题。

听起来更像是你需要一个权限概念。用户可能有权查看某些字段。基于此,您可以使用java bean introspection在发送到客户端之前清除这些字段的值。

然而,这也可能有问题。客户应该能够确定它是否有权查看该字段。

相关问题