Is this code valid?
public abstract class A {
protected static final String c = "my const";
}
#myAnnotation(value=A.c)
public class B extends A {
}
Eclipse with JDK 1.6.0.23 accepts this, but Maven 2.2.1 with JDK 1.6.0.23 shows me the following compile error:
c has protected access in A
Thanks to the comment from #adranale I found a different answer in the Java Language Specification section on Access Control. I don't think it should work this way, but the relevant text regarding "protected" reads
Let C be the class in which a protected member m is declared. Access is permitted only within the body of a subclass S of C.
The body of a class is all the code in curly brackets. Class anotations are outside the curly brackets, so they don't have access. Interestingly, this logic would not apply to method, parameter, field or local variable annotations which are inside the class body.
I think I see what is happening here. An instance of an annotations is effectively an interface with a unique static initializer. The only things the annotation spec adds on top are syntactic sugar and a link to the method, class or field. So when you type value=c.A that is almost like adding a static initilizer to the annotation. The annotation is not a subclass of A, so access is denied. Protected access includes package access, so when you move A into the same package as B the annotation is also in the same package as A. It gets access. Very good question and I think the behavior should be the same for both compilers. I think Eclipse will let you customize what it treats as an error so you might be able to make them agree to both use the undesirable, more restrictive behavior.
The Annotation you are trying to fill with the "const" tries to access the class from outside by using protected that can't work. Eclipse uses it's own compiler so you should try to make clean rebuild in Eclipse to see if it's working. I assume it will not.
This code will compile only if both A and B belong to the same package.
Related
It is possible in plain Java to override a method of a class
programmatically at runtime (or even create a new method)?
I want to be able to do this even if I don't know the classes at compile time.
What I mean exactly by overriding at runtime:
abstract class MyClass{
public void myMethod();
}
class Overrider extends MyClass{
#Override
public void myMethod(){}
}
class Injector{
public static void myMethod(){ // STATIC !!!
// do actual stuff
}
}
// some magic code goes here
Overrider altered = doMagic(
MyClass.class, Overrider.class, Injector.class);
Now, this invocation...
altered.myMethod();
...would call Injector.myMethod() instead of Overrider.myMethod().
Injector.myMethod() is static, because, after doing "magic"
it is invoked from different class instance (it's the Overrider),
(so we prevent it from accessing local fields).
You can use something like cglib for generating code on-the-fly
In java6 has been added the possibility to transform any already loaded class. Take a look at the changes in the java.lang.instrument package
For interfaces there is java.lang.reflect.Proxy.
For classes you'll either need a third-party library or write a fair bit of code. Generally dynamically creating classes in this way is to create mocks for testing.
There is also the instrumentation API that allows modification of classes. You can also modify classes with a custom class loader or just the class files on disk.
I wrote an article for java.net about how to transparently add logging statements to a class when it is loaded by the classloader using a java agent.
It uses the Javassist library to manipulate the byte code, including using the Javassist compiler to generate extra bytecode which is then inserted in the appropriate place, and then the resulting class is provided to the classloader.
A refined version is available with the slf4j project.
If I got it right, the main problem that concerns you is how to pass a static method delegate (like in C#), through the instance interface method.
You can check this article: A Java Programmer Looks at C# Delegates (archived), which shows you how to get a reference to your static method and invoke it. You can then create a wrapper class which accepts the static method name in its constructor, and implements your base class to invoke the static method from the instance method.
I have come across the #JvmSynthetic annotation in kotlin-stdlib, and I'm wondering what it is for, but, unfortunately, it is undocumented. (UPD: it was at that moment)
As far as I understand, applying it to a program element will add the synthetic modifier to the corresponding bytecode elements. As a consequence, the element becomes invisible from Java:
class MyClass {
#JvmSynthetic
fun f() { }
}
Somewhere in Java code:
MyClass c = new MyClass();
c.f() // Error: cannot resolve method f()
But the same elements are still visible in Kotlin code:
val c = MyClass()
c.f() // OK
Is hiding declarations from non-Kotlin sources a valid use of #JvmSynthetic? Is it the intended use? What are the other appropriate use cases?
Since #JvmSynthetic hides functions from Java, they cannot be overridden in Java either (and when it comes to an abstract member, the calls then result into AbstractMethodError). Given that, can I use #JvmSynthetic to prohibit overriding members of a Kotlin class in Java sources?
In plain Java, synthetic methods are generated by the javac compiler. Normally the compiler must create synthetic methods on nested classes, when fields specified with the private modifier are accessed by the enclosing class.
Given the following class in java:
public final class SyntheticSample
{
public static void main(final String[] args)
{
SyntheticSample.Nested nested = new SyntheticSample.Nested();
out.println("String: " + nested.syntheticString);
}
private static final class Nested
{
private String syntheticString = "I'll become a method!";
}
}
when the SyntheticSample class accesses the nested.syntheticString field, it is indeed calling a static synthetic method generated by the compiler (named something like access$100).
Even if Kotlin exposes a #JvmSynthetic annotation that is able to "force" the creation of synthetic methods, I advice to not using it in normal "user" code. Synthetic methods are low-level tricks made by the compiler, and we should never rely on such things in everyday code. I think it's there to support other parts of the standard library, but you should ask the JetBrains guys directly if you're curious (try on the official Kotlin Discussion Forum)
First, to answer what synthetic methods actually are, let's have a look at the Java language specification:
11. A construct emitted by a Java compiler must be marked as synthetic if it does not correspond to a construct declared explicitly or implicitly in source code, unless the emitted construct is a class initialization method (JVMS §2.9).
The #JvmSynthetic annotation does exactly that: prevent access from source code. The method will still appear in reflection and is then marked as synthetic.
More precisely, from the Kotlin documentation (emphasis mine):
#JvmSynthetic
Sets ACC_SYNTHETIC flag on the annotated target in the Java bytecode.
Synthetic targets become inaccessible for Java sources at compile time while still being accessible for Kotlin sources. Marking target as synthetic is a binary compatible change, already compiled Java code will be able to access such target.
This annotation is intended for rare cases when API designer needs to hide Kotlin-specific target from Java API while keeping it a part of Kotlin API so the resulting API is idiomatic for both.
As described in the last paragraph, #JvmSynthetic is a tool for API design, which lets a library writer avoid automatic generation of Java equivalents. Probably the most popular use cases are Kotlin-only features, such as operator overloading, componentN() methods or properties, which may have a more idiomatic way to be exposed in Java.
It is noteworthy that the target of this annotations are property setters/getters, functions and fields -- basically everything that translates in Java to a method.
#Target([
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
AnnotationTarget.FIELD])
annotation actual class JvmSynthetic
Ok, let me start it with the following example to get a brief example
public class ClassA{
______ static final String MODULE = "[ClassA]";
}
in the blank space, I came across many code snippet it has some times public or protected or private but could not understand the which one is the best and why?.I know protected is best for subclass implementation but then subclass to has MODULE variable.
basically MODULE is used in logging activities like for example
System.out.println(MODULE+"given message");
in-short which is best way to use for accessing?
Like anything, you should give it the strictest access level that makes sense.
If it will only be used inside the class, use private. If it will only be used inside the package, use package access. If it could be used in subclasses, use protected. If it could be used by anyone, use public.
This applies to every class member in every programming language - it is by no means specific to fields named MODULE in Java.
Basically MODULE is used in logging activities...
Then I would suggest to make it private, because it will not be used outside the class (assuming that other classes have similar static constants).
I am trying to write tests for a piece of code that uses the inner class of the following object as an input (I've generalized the names).
public class MockOuterClass implements OuterClass, Mock {
static class MockInnerClass implements InnerClass {
//fields and methods of the nested class
}
//methods of the outer class
}
Now since the inner class does not have a visibility tag, it defaults to "protected." Here lies my issue: since my tests and source code are in separate packages, how can I create an instance of this inner object? I attempted this:
MockOuterClass.MockInnerClass test = new MockOuterClass.MockInnerClass();
When I do this, Eclipse says that this line is unacceptable (which I assumed was the case, but it was wishful thinking) since MockInnerClass defaults to protected and thus cannot be used outside its package. Is there a way I can use this class somehow? I did not write the source code, so I am unsure if the lack of a "public" tag on the inner class was intentional or the programmer's mistake.
Thank you in advance.
A bit of an aside, not an actual answer, but I have always put my tests into the same package as the classes being tested. At least, as much as possible, there are a few very rare cases where this is impossible.
Why are you using a different package? Is there a good reason to do so?
Now, back to an answer, if you insist on testing from a separate package, unless MockOuterClass exposes some method to construct (or expose) the MockInnerClass, you are stuck. (I guess you could try using Reflection but that is getting desperate.) However, as several have commented, the author of the class "intended" for the inner class to be hidden, a. la. Kent Beck.
In other words, if you follow Kent Beck, you should be writing tests that target MockOuterClass, NOT MockInnerClass. The inner class is a "non public detail".
If this code wasn't written by you and declares a non-public static class (side-note: it defaults to package-protected, which is very different to protected), chances are the writer intends to hide the class from your use. In short, there is no way to access the class from outside the package, and you probably shouldn't be trying to.
This question already has answers here:
Why are modifiers allowed for a package when they don't seem to do anything?
(2 answers)
Closed 9 years ago.
Please see the sample:
private package com.xm.aws;
import static com.xml.aws.PcgTest.test;
public class PackageTest {
public static void main(String[] args) {
test(args);
}
}
What does the private tell me about the package?
Let's not confuse this with package-private or other access modifiers that can be added to classes, methods and fields.
The Java language specification clearly states:
6.6.1. Determining Accessibility
A package is always accessible.
Looking at that, the only answer, that comes to my mind is, that (some) compilers don't treat this as a compiletime error but that it is completely meaningless. It is not possible to restrict accessibility to a class or package that way (and every package is always accessible).
Another section from the java language spec:
7.4.1. Named Packages
A package declaration in a compilation unit specifies the name (§6.2)
of the package to which the compilation unit belongs.
PackageDeclaration:
Annotationsopt package PackageName ;
So the keyword may be preceeded by annotations. But the access modifiers is not part of the package declaration. And even if we expand on "Annotations" we won't find access modifiers here.
Another reference, according to JLS 18. Syntax the only thing allowed to precede package is an Annotation.
CompilationUnit:
[[Annotations] package QualifiedIdentifier ;]
{ImportDeclaration} {TypeDeclaration}
The code sample you have provided is not valid in java. The private access modifier can be applied to members and methods, including inner classes. Your code compiles in Eclipse, but is rejected by Oracle's own compiler.
In fact, the byte-code generated by Eclipse for this java code, is exactly the same with or without that private keyword. This shows that this is probably an Eclipse bug where it ignores the text before the word package during compilation.
What you have probably read or heard, is the phrase "package-private", which means that nothing outside the package can access the class or member. You do this by not using any access modifier on the class itself. Not by using the private keyword on the package.
If you add private before the package name this will be compiler error
Though package is not the highest degree of Encapsulation in Java which is achieved using private keyword, it still second best option and must to encapsulate whole functionality rather than just a class.
In short, Access modifiers are not part of the package declarations
Refer this link
Looks to me like it is only happening in eclipse. When i compile the code though javac command through command prompt, i get this compile time error:
error: class, interface, or enum expected
Looking at the post here, looks like eclipse uses its own jdk:
Do I need to install java sdk if I have eclipse
Writing "private package" and "package" is the same. They identify the same access level (the dafault one).
The private modifier specifies that the member can only be accessed within its own package (as with protected).