How does the java accessibility (or perhaps, scope) work with respect to type import multi-level nested classes? An example:
ClassA.java:
package com.oracle.javatests;
public class ClassA {
public static class NestedAA {
public void printSomething() {
System.out.println("inside " + this.getClass().getName());
}
public static class NestedAB{
public void printSomethingAB() {
System.out.println("inside " + this.getClass().getName());
}
}
}
public void printSomething() {
System.out.println("inside " + this.getClass().getName());
}
}
Main.java
package com.oracle.javatests;
import com.oracle.javatests.ClassA.*;
// import com.oracle.javatests.ClassA.NestedAA.*; // Adding this will resolve NestedAB
public class Main {
public static void main (String[] args){
ClassA objA = new ClassA();
objA.printSomething();
NestedAA nestedAA = new NestedAA(); // Ok
NestedAB nestedAB = new NestedAB(); // Compiler error- NestedAB cannot be resolved to a type
}
}
The import statement does not import NestedAB type when using wildcards. A perhaps similar question led me to the java spec sheet which clarifies Type-Import-on-Demand Declarations :
A type-import-on-demand declaration allows all accessible types of a
named package or type to be imported as needed.
The accepted answer to the question implies that the on demand import declarations are not recursive. The reasoning is perhaps what Java considers "all accessible types of a named type", and the general concept of packages but I am falling short of connecting the dots and understand what accessible types means with respect to nested classes.
Can please anyone help explain how the type import and accessibility seem to work in java (while ignoring the arguable use of wildcard imports)
It's not heard to understand. import static com.foo.bar.*; is the exact same thing as import static com.foo.bar.[everything you can imagine here but without dots].
In other words, in your example, with import static pkg.ClassA.*; you can just write NestedAA without qualifiers and that works, because import static pkg.ClassA.NestedAA; would have made that work just the same.
You cannot write NestedAB unqualified and expect that to work; there is nothing you could possibly write instead of a * (which doesn't include dots) that would make that work, therefore, a star import doesn't make it work either.
Related
I was having trouble getting com.sun.jna.Structure to work, so I tried copying the first JNA test I found and I can't even get that to work.
For convenience, try it online.
import com.sun.jna.Structure;
import java.util.Arrays;
import java.util.List;
public class MyClass {
public void testSimpleSize() throws Exception {
class TestStructure extends Structure {
public int field;
#Override
protected List<String> getFieldOrder() {
return Arrays.asList("field");
}
}
Structure s = new TestStructure();
//assertEquals("Wrong size", 4, s.size());
}
public static void main(String[] args)
{
try
{
new MyClass().testSimpleSize();
}
catch (Exception e)
{
System.out.println(e);
}
}
}
The code compiles ok, but when running I get
Exception in thread "main" java.lang.Error: Exception reading field 'field' in class MyClass$1TestStructure
at com.sun.jna.Structure.getFieldValue(Structure.java:639)
at com.sun.jna.Structure.deriveLayout(Structure.java:1285)
at com.sun.jna.Structure.calculateSize(Structure.java:1159)
at com.sun.jna.Structure.calculateSize(Structure.java:1111)
at com.sun.jna.Structure.allocateMemory(Structure.java:414)
at com.sun.jna.Structure.<init>(Structure.java:205)
at com.sun.jna.Structure.<init>(Structure.java:193)
at com.sun.jna.Structure.<init>(Structure.java:180)
at com.sun.jna.Structure.<init>(Structure.java:172)
at MyClass$1TestStructure.<init>(MyClass.java:8)
at MyClass.testSimpleSize(MyClass.java:15)
at MyClass.main(MyClass.java:23)
Caused by: java.lang.IllegalAccessException: class com.sun.jna.Structure cannot access a member of class MyClass$1TestStructure with modifiers "public"
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:361)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:591)
at java.base/java.lang.reflect.Field.checkAccess(Field.java:1075)
at java.base/java.lang.reflect.Field.get(Field.java:416)
at com.sun.jna.Structure.getFieldValue(Structure.java:636)
... 11 more
Am I missing something?
As you've discovered in your answer, the root cause of the problem (as indicated by the stack trace) was lack of reflective access to your class. While your answer solves your specific issue, I wanted to expand on more possible reasons this could occur, which may help others.
The reason the JNA test case you linked to works is because the test resides in the same package as the Structure class, which gives the Structure class access to package private classes. In your case, the inner class TestStructure does not have the public modifier, and resides in a different package than com.sun.jna.Structure.
You solved the problem by moving the class to an accessible location, which works. Most often in JNA implementations, structures are declared in interfaces (and thus are by default public).
A second possibility of getting this error is if you are using Java Modules (JPMS). Java Modules do not permit reflective access by default, so it must be explicitly allowed in the module-info.java class, either with opens your.package to com.sun.jna; (to allow runtime-only reflection including private members) or exports your.package to com.sun.jna; (to allow compile-time and run-time public access). While this does not apply in your case (you're using the default package which would be in the unnamed module) this may be something you may encounter in the future if you create a modular project.
I have found a solution and it was much simpler than I thought.
According to the documentation,
An IllegalAccessException is thrown when an application tries to reflectively create an instance (other than an array), set or get a field, or invoke a method, but the currently executing method does not have access to the definition of the specified class, field, method or constructor.
Which means that com.sun.jna.Structure needs to have access to TestStructure, in order to use reflection (which it needs in order to get the struct fields). The simplest way to solve that is to move TestStructure out of the function and make it public. Like this:
import com.sun.jna.Structure;
import java.util.Arrays;
import java.util.List;
public class MyClass {
public class TestStructure extends Structure {
public int field;
#Override
protected List<String> getFieldOrder() {
return Arrays.asList("field");
}
}
public void testSimpleSize() throws Exception {
Structure s = new TestStructure();
//assertEquals("Wrong size", 4, s.size());
}
public static void main(String[] args)
{
try
{
new MyClass().testSimpleSize();
}
catch (Exception e)
{
System.out.println(e);
}
}
}
There may be a better solution, but this is the simplest and works for me.
I am studying for my BS, and my professor has given me a task, he said: Create a class without using any access modifier or interface keyword whose object can't be created.
I went through Google but can't find the solution. How can this be done in Java?
Enums are classes (JLS§8.9) that cannot be instantiated and cannot be subclassed; just create one without any values:
enum Foo {}
Other possibilities depending on interpretation:
JonK and T.J. Crowder considered throwing an exception from the constructor:
final class Example {
Example() {
throw new Exception();
}
}
But nick zoum pointed out that an instance is still created and exists, briefly, prior to the exception, even though it cannot (in the example above) be retained.
nick zoum considered abstract:
abstract class Example {
}
...but T.J. Crowder pointed out that abstract classes can be subclassed (they cannot be final), and a subclass instance "is a" superclass instance.
I'm not a Java person, but other answers gave me this idea:
import java.util.*;
import java.lang.*;
import java.io.*;
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
Object o = new Problematic();
// unreachable
}
}
class Problematic
{
static
{
int i = 1 / 0 ;
}
}
Try it on ideone
I'm pretty sure there's no way of making a Problematic and surviving...
(Note that when I tried throw new Exception(); in the static initializer it wouldn't compile)
Have you tried the keyword abstract?
For example:
abstract class Test{}
Of course this can be overwritten, so please check this answer for a more foolproof design.
Without hearing exactly how your professor phrased it, "without using any access-modifier" might mean they are attempting to teach you how the "default" access modifier works?
In which case:
package mypackage.nocreate;
class MyClass {
}
And then:
package mypackage;
import mypackage.nocreate.MyClass;
public class Test {
public static void main(String[] args) {
new MyClass(); // not allowed - in a different package
}
}
You could argue that - in the source code at least - that doesn't use any access modifier :)
Anonymous inner class should be the answer.
Example:
public abstract class HelloWorld{
abstract void x();
public static void main(String []args){
System.out.println("Hello World");
HelloWorld h = new HelloWorld(){
void x(){
System.out.println(" ");
}
};
h.x();
}
}
A class is created, but it's name is decided by the compiler which extends the HelloWorld class and provides the implementation of the x() method.
Why does Java allow me to exclude the import statement for MyClass in the following case. Also there must not be any other explicit declarations of MyClass in the rest of the class. It seems like javac should not allow the import to be missing.
public class MyClassDao {
public List<MyClass> getAll(){....}
}
// no import needed here for MyClass
public class RandomService {
....
void process(){
myModel.setMyClassList(myClassDao.getAll());
}
}
As the Java Language Specification states
An import declaration allows a named type or a static member to be
referred to by a simple name (§6.2) that consists of a single
identifier.
You are not referring to the name MyClass, so no import statement is needed.
I have imported an Existing Java Application into my Workspace .
I see that , a class with same name is present in different packages with in the Application.
For example a class named "Status.java" is present with in
com.tata.model.common.Status;
com.bayer.frontlayer.dao.Status;
When I tried to use both of them within a class, for example as shown below
import com.tata.model.common.Status;
import com.bayer.frontlayer.dao.Status;
public class Adapter
{
}
It started giving an error in Eclipse stating
The import com.bayer.frontlayer.dao.Status collides with another import statement
Is there anyway to solve this without changing the name of the classes??
Thank you.
You can use them explicitly without importing them, so the included package name differentiates between the two:
//No imports required!
public class Adapter
{
private com.tata.model.common.Status x;
private com.bayer.frontlayer.dao.Status y;
}
You can import just one of the classes and use the fully qualified name for the other one.
e.g.
import com.tata.model.common.Status;
//import com.bayer.frontlayer.dao.Status;
class SomeClass{
void someMethod(){
new Status(); // com.tata.model.common.Status
new com.bayer.frontlayer.dao.Status(); //com.bayer.frontlayer.dao.Status
}
}
Though I think it would be less confusing in your case if you just used the fully-qualified names for both classes.
Directly apply full Class Names wherever applicable. Eg-
public class SomeClass {
public someMethod() {
com.myapp.someotherpackage.Status = "something";
com.some.other.package.Status = "otherthing";
if(com.myapp.someotherpackage.Status == com.some.other.package.Status) {
}
....
}
}
This is the test:
import static junit.framework.Assert.assertTrue;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.whenNew;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest( {ClassUnderTesting.class} )
public class ClassUnderTestingTest {
#Test
public void shouldInitializeMocks() throws Exception {
CollaboratorToBeMocked mockedCollaborator = mock(CollaboratorToBeMocked.class);
suppress(constructor(CollaboratorToBeMocked.class, InjectedIntoCollaborator.class));
whenNew(CollaboratorToBeMocked.class)
.withArguments(InjectedAsTypeIntoCollaborator.class)
.thenReturn(mockedCollaborator);
new ClassUnderTesting().methodUnderTesting();
assertTrue(true);
}
}
These are the classes :
public class ClassUnderTesting {
public void methodUnderTesting() {
new CollaboratorToBeMocked(InjectedAsTypeIntoCollaborator.class);
}
}
public class CollaboratorToBeMocked {
public CollaboratorToBeMocked(Class<InjectedAsTypeIntoCollaborator> clazz) {
}
public CollaboratorToBeMocked(InjectedIntoCollaborator someCollaborator) {
}
public CollaboratorToBeMocked() {
}
}
public class InjectedAsTypeIntoCollaborator {
}
public class InjectedIntoCollaborator {
}
This is the error :
org.powermock.reflect.exceptions.TooManyConstructorsFoundException: Several matching constructors found, please specify the argument parameter types so that PowerMock can determine which method you're refering to.
Matching constructors in class CollaboratorToBeMocked were:
CollaboratorToBeMocked( InjectedIntoCollaborator.class )
CollaboratorToBeMocked( java.lang.Class.class )
Here comes the question: how can I make PowerMock figure out what constructor to look for?
The problematic line is the suppress. That is where the error comes from.
Perhaps it is too late for your question. I met it today and found the solution at the following url. Basically, you need to specify your argument type like.
whenNew(MimeMessage.class).**withParameterTypes(MyParameterType.class)**.withArguments(isA(MyParameter.class)).thenReturn(mimeMessageMock);
http://groups.google.com/group/powermock/msg/347f6ef1fb34d946?pli=1
Hope it can help you. :)
I didn't know of PowerMock until you wrote your question, but did some reading and found this in their documentation. Still I am not really sure if that helps you:
If the super class have several
constructors it's possible to tell
PowerMock to only suppress a specific
one. Let's say you have a class called
ClassWithSeveralConstructors that has
one constructor that takes a String
and another constructor that takes an
int as an argument and you only want
to suppress the String constructor.
You can do this using the
suppress(constructor(ClassWithSeveralConstructors.class, String.class));
method.
found at http://code.google.com/p/powermock/wiki/SuppressUnwantedBehavior
Isn't it the thing you wanted?
EDIT: Now I see, you've already tried suppressing. But are you sure you got the suppress call right? Isn't the first argument of constructor() supposed to be the class you would like to surpress the constructor in?
If using PowerMock for EasyMock you can do PowerMock.expectNew(CollaboratorToBeMocked.class, new Class[]{InjectedIntoCollaborator.class}, ...) where the Class[] is the parameter types of the constructor you're expecting to be called. This will resolve the ambiguity between the constructors.