如何避免内部类访问受保护的外部类超类时出现"IllegalAccessError"错误

5

我在Spring控制器中使用了内部类。它在访问其父类的超类的受保护字段/方法时出现问题。

研究表明,这可能是由于不同的类加载器造成的,但我对Spring不太了解,无法确定。

class SuperBaseController {
    protected String aField;

    protected void aMethod() {

    }
}

@Controller
class OuterMyController extends SuperBaseController {

    class Inner {

        public void itsMethod() {
            // java.lang.IllegalAccessError: tried to access method
            aMethod();
        }

        public void getField() {
            // java.lang.IllegalAccessError: tried to access field
            String s = aField;
        }
    }

    void doSomething () {
        // Obviously fine.
        aMethod();
        // Fails in the Inner method call.
        new Inner().itsMethod();

        // Obviously fine.
        String s = aField;
        // Fails in the Inner method call.
        new Inner().getField();
    }
}

是否有简单的技巧来避免/修复此问题?最好不要涉及使字段/方法 public

我确认外部类的ClassLoader属性与超类不同。


@daniu - 是的,它可以。 - OldCurmudgeon
1
你使用的编译器(及版本)是什么? - Erwin Bolwidt
1
@ErwinBolwidt - Java 1.8.0_151 (目标版本 1.7) - Spring 3.0.7 - OldCurmudgeon
1
你在谈论类加载器,那么这是否是由于Spring使用一个类加载器来加载MyController(显然Spring会加载该控制器类),并且由于Inner直到需要时才会被加载,所以它将使用另一个类加载器进行加载?如果你在@PostConstruct方法中调用Inner,会触发类加载,能够正常工作吗? - Kayaman
3
您能否张贴精确的堆栈跟踪(至少前几行)?错误应该起源于编译器在 MyController 类中创建的合成访问器方法。具体细节将给出造成问题的提示。 - Erwin Bolwidt
显示剩余4条评论
3个回答

0

我创建了以下类:

public class BaseController
{
    protected String field;
    protected void method()
    {
        System.out.println("I'm protected method");
    }
}

@RestController
@RequestMapping("/stack")
public class StackController extends BaseController
{
    class Inner
    {
        public void methodInvocation()
        {
            method();
        }
        public void fieldInvocation()
        {
            field = "Test";
        }
    }
    @RequestMapping(value= {"/invoca"}, method= {RequestMethod.GET})
    public ResponseEntity<String> invocation()
    {
        Inner in = new Inner();
        in.fieldInvocation();
        in.methodInvocation();
        return new ResponseEntity<String>("OK", HttpStatus.OK);
    }
}

我尝试调用REST服务,没有任何问题。现在我正在使用这个Spring配置(基于注释的注释):

@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = { "it.spring.controller" })
@PropertySource( value={"classpath:config.properties"}, encoding="UTF-8", ignoreResourceNotFound=false)
public class DbConfig
{
}


@Configuration
@EnableWebMvc
@Import(DbConfig.class)
@PropertySource(value = { "classpath:config.properties" }, encoding = "UTF-8", ignoreResourceNotFound = false)
public class WebMvcConfig extends WebMvcConfigurerAdapter
{
}

正如您所看到的,我使用了@Import注释,并在我的web.xml中使用了以下配置:

<servlet>
    <servlet-name>SpringDispSvlt</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </init-param>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>it.WebMvcConfig</param-value>
    </init-param>
    <init-param>
        <param-name>dispatchOptionsRequest</param-name>
        <param-value>true</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <async-supported>true</async-supported>
</servlet>

通过使用这个配置,我在内部类中调用受保护的字段和/或方法时没有任何问题。

如果您无法将您的配置适应此配置...您可以发布您使用的配置吗?

希望这对您有用

安吉洛


0

这样怎么样:

class OuterMyController extends SuperBaseController {
    private String getAField() { return super.aField; }
    protected void aMethod() { super.aMethod(); }
    ...
}

现在内部类使用其外部类的方法,因此不存在非法访问,而外部类的方法可以访问基类的受保护字段。


0
class SuperBaseController {
protected String aField;

protected void aMethod() {

    }
}

@Controller
class OuterMyController extends SuperBaseController {


    public void itsMethod() {
        aMethod();
    }

    public void getField() {
        String s = aField;
    }

class Inner {
    public void innerItsMethod() {
        itsMethod();
    }
    public void innerGetField() {
    String s = getField();
    }
}

void doSomething () {
    aMethod();
    new Inner().itsMethod();
    String s = aField;
    new Inner().getField();
    }
}

这个能用吗?

另外,你可能需要定义运行该方法的对象。 (例如:Inner.getField() 或 SuperBaseController.aMethod())


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接