Is there any way to get a classes declared fields (and methods) in the order of declaration using reflection? According to the documentation, the ordering of Methods and Fields returned by getFields(), getDeclaredFields(), etc. is undefined.
Specifying something like an index would be possible using annotation as suggested in Java reflection: Is the order of class fields and methods standardized?
Are there any better options, i.e. not having to specify the index manually?
Now before you ask what I need this for: we have a method that takes a quite big data structure as input and performs a lengthy calculation on it. To create unit tests, we made a method that takes an input object and an output instance and creates the Java source code (setting up input, invoking the calculation method, and asserting the correct results afterwards) as output. This code is much more readable when fields are written in declaration order.
With jdk 6, the reflected fields are in deed in their declaration order. In early jdk that wasn't the case. Apparently enough people have nagged.
Although not guaranteed by javadoc, I would still take this order as granted, and I assume the order will be kept in future jdks too.
In your app, like in most apps, the dependency on the declaration order is mostly vanity - your app won't fail if the order screws up, it just become a little uglier.
I had this as an isolated problem, look at
https://github.com/wmacevoy/kiss/blob/master/src/main/java/kiss/util/Reflect.java
and the method
public static Method[] getDeclaredMethodsInOrder(Class clazz)
It gets the order by looking at the bytecode of the class. If you just want to use the libray, is would be
kiss.util.Reflect.getDeclaredMethodsInOrder(Test.class)
No, not possible with reflection. You could however solve it using a ProcessBuilder and the javap command:
Given a Test.java:
public abstract class Test {
public void method1() {
}
public void method2() {
}
public static void main(String[] args) {
}
public String method3() {
return "hello";
}
abstract void method4();
final int method5() {
return 0;
}
}
The command javap Test prints:
...
public Test();
public void method1();
public void method2();
public static void main(java.lang.String[]);
public java.lang.String method3();
abstract void method4();
final int method5();
...
I'm afraid it's impossible without modifying the compilation process. Normally, the field get written into the classfile in any order and the information about the declaration order gets lost.
Most probably you could use an annotation processor to write the order in an auxiliary file.
It should be quite easy. Look e.g. at interfacegen for an example, how an annotation processor can work. You may want to put the information in the same file, but this is much harder.
You may think about using Javadoc with a custom Doclet, but this requires the source to be available.
There still is no guarantee about the order in the API (methods, fields, but every javadoc output I've ever seen has them in the right order, so I suppose the doclets get them in declaration order.
You won't be able to get the information from the class file. As Adam said in an answer to the refrenced other question:
The elements in the array returned are not sorted and are not in any particular order.
And "no order" includes "no declaration order".
I once used a Java source file parser to get input data for code generators. And this way you'll have fields and methods in declaration order.
Related
I'm sure you all know the behaviour I mean - code such as:
Thread thread = new Thread();
int activeCount = thread.activeCount();
provokes a compiler warning. Why isn't it an error?
EDIT:
To be clear: question has nothing to do with Threads. I realise Thread examples are often given when discussing this because of the potential to really mess things up with them. But really the problem is that such usage is always nonsense and you can't (competently) write such a call and mean it. Any example of this type of method call would be barmy. Here's another:
String hello = "hello";
String number123AsString = hello.valueOf(123);
Which makes it look as if each String instance comes with a "String valueOf(int i)" method.
Basically I believe the Java designers made a mistake when they designed the language, and it's too late to fix it due to the compatibility issues involved. Yes, it can lead to very misleading code. Yes, you should avoid it. Yes, you should make sure your IDE is configured to treat it as an error, IMO. Should you ever design a language yourself, bear it in mind as an example of the kind of thing to avoid :)
Just to respond to DJClayworth's point, here's what's allowed in C#:
public class Foo
{
public static void Bar()
{
}
}
public class Abc
{
public void Test()
{
// Static methods in the same class and base classes
// (and outer classes) are available, with no
// qualification
Def();
// Static methods in other classes are available via
// the class name
Foo.Bar();
Abc abc = new Abc();
// This would *not* be legal. It being legal has no benefit,
// and just allows misleading code
// abc.Def();
}
public static void Def()
{
}
}
Why do I think it's misleading? Because if I look at code someVariable.SomeMethod() I expect it to use the value of someVariable. If SomeMethod() is a static method, that expectation is invalid; the code is tricking me. How can that possibly be a good thing?
Bizarrely enough, Java won't let you use a potentially uninitialized variable to call a static method, despite the fact that the only information it's going to use is the declared type of the variable. It's an inconsistent and unhelpful mess. Why allow it?
EDIT: This edit is a response to Clayton's answer, which claims it allows inheritance for static methods. It doesn't. Static methods just aren't polymorphic. Here's a short but complete program to demonstrate that:
class Base
{
static void foo()
{
System.out.println("Base.foo()");
}
}
class Derived extends Base
{
static void foo()
{
System.out.println("Derived.foo()");
}
}
public class Test
{
public static void main(String[] args)
{
Base b = new Derived();
b.foo(); // Prints "Base.foo()"
b = null;
b.foo(); // Still prints "Base.foo()"
}
}
As you can see, the execution-time value of b is completely ignored.
Why should it be an error? The instance has access to all the static methods. The static methods can't change the state of the instance (trying to is a compile error).
The problem with the well-known example that you give is very specific to threads, not static method calls. It looks as though you're getting the activeCount() for the thread referred to by thread, but you're really getting the count for the calling thread. This is a logical error that you as a programmer are making. Issuing a warning is the appropriate thing for the compiler to do in this case. It's up to you to heed the warning and fix your code.
EDIT: I realize that the syntax of the language is what's allowing you to write misleading code, but remember that the compiler and its warnings are part of the language too. The language allows you to do something that the compiler considers dubious, but it gives you the warning to make sure you're aware that it could cause problems.
They cannot make it an error anymore, because of all the code that is already out there.
I am with you on that it should be an error.
Maybe there should be an option/profile for the compiler to upgrade some warnings to errors.
Update: When they introduced the assert keyword in 1.4, which has similar potential compatibility issues with old code, they made it available only if you explicitly set the source mode to "1.4". I suppose one could make a it an error in a new source mode "java 7". But I doubt they would do it, considering that all the hassle it would cause. As others have pointed out, it is not strictly necessary to prevent you from writing confusing code. And language changes to Java should be limited to the strictly necessary at this point.
Short answer - the language allows it, so its not an error.
The really important thing, from the compiler's perspective, is that it be able to resolve symbols. In the case of a static method, it needs to know what class to look in for it -- since it's not associated with any particular object. Java's designers obviously decided that since they could determine the class of an object, they could also resolve the class of any static method for that object from any instance of the object. They choose to allow this -- swayed, perhaps, by #TofuBeer's observation -- to give the programmer some convenience. Other language designers have made different choices. I probably would have fallen into the latter camp, but it's not that big of a deal to me. I probably would allow the usage that #TofuBeer mentions, but having allowed it my position on not allowing access from an instance variable is less tenable.
Likely for the same logical that makes this not an error:
public class X
{
public static void foo()
{
}
public void bar()
{
foo(); // no need to do X.foo();
}
}
It isn't an error because it's part of the spec, but you're obviously asking about the rationale, which we can all guess at.
My guess is that the source of this is actually to allow a method in a class to invoke a static method in the same class without the hassle. Since calling x() is legal (even without the self class name), calling this.x() should be legal as well, and therefore calling via any object was made legal as well.
This also helps encourage users to turn private functions into static if they don't change the state.
Besides, compilers generally try to avoid declaring errors when there is no way that this could lead to a direct error. Since a static method does not change the state or care about the invoking object, it does not cause an actual error (just confusion) to allow this. A warning suffices.
The purpose of the instance variable reference is only to supply the type which encloses the static. If you look at the byte code invoking a static via instance.staticMethod or EnclosingClass.staticMethod produces the same invoke static method bytecode. No reference to the instance appears.
The answer as too why it's in there, well it just is. As long as you use the class. and not via an instance you will help avoid confusion in the future.
Probably you can change it in your IDE (in Eclipse Preferences -> Java -> Compiler -> Errors/Warnings)
There's not option for it. In java (like many other lang.) you can have access to all static members of a class through its class name or instance object of that class. That would be up to you and your case and software solution which one you should use that gives you more readability.
It's pretty old topic but still up-to-date and surprisingly bringing higher impact nowadays. As Jon mentioned, it might be just a mistake Java's designers made at the very beginning. But I wouldn't imagine before it can have impact on security.
Many coders know Apache Velocity, flexible and powerful template engine. It's so powerful that it allows to feed template with a set of named objects - stricly considered as objects from programming language (Java originally). Those objects can be accessed from within template like in programming language so for example Java's String instance can be used with all its public fields, properties and methods
$input.isEmpty()
where input is a String, runs directly through JVM and returns true or false to Velocity parser's output). So far so good.
But in Java all objects inherit from Object so our end-users can also put this to the template
$input.getClass()
to get an instance of String Class.
And with this reference they can also call a static method forName(String) on this
$input.getClass().forName("java.io.FileDescriptor")
use any class name and use it to whatever web server's account can do (deface, steal DB content, inspect config files, ...)
This exploit is somehow (in specific context) described here: https://github.com/veracode-research/solr-injection#7-cve-2019-17558-rce-via-velocity-template-by-_s00py
It wouldn't be possible if calling static methods from reference to the instance of class was prohibited.
I'm not saying that a particular programming framework is better than the other one or so but I just want to put a comparison. There's a port of Apache Velocity for .NET. In C# it's not possible to call static methods just from instance's reference what makes exploit like this useless:
$input.GetType().GetType("System.IO.FileStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
I just consider this:
instanceVar.staticMethod();
to be shorthand for this:
instanceVar.getClass().staticMethod();
If you always had to do this:
SomeClass.staticMethod();
then you wouldn't be able to leverage inheritance for static methods.
That is, by calling the static method via the instance you don't need to know what concrete class the instance is at compile time, only that it implements staticMethod() somewhere along the inheritance chain.
EDIT: This answer is wrong. See comments for details.
class Elephant extends Animal {
public Elephant(String name) {
super(name);
}
void makeNoise() {
logger.info(" Elephant make Sound");
}
void perform(String day) {
if (day.equals("thursday") || day.equals("friday")) {
makeNoise();
}
}
}
Now i want to test the perform method. How can I unit test this method using JUnit?
Solution with Mockito Spy
import org.junit.Test;
import static org.mockito.Mockito.*;
public class ElephantTest {
#Test
public void shouldMakeNoise() throws Exception {
//given
Elephant elephant = spy(new Elephant("foo"));
//when
elephant.perform("friday");
//then
verify(elephant).makeNoise();
}
}
Negative tests:
#Test
public void elephantShouldDontMakeNoisesOnMonday() {
//given
Elephant elephant = spy(new Elephant("foo"));
//when
elephant.perform("monday");
//then
verify(elephant, never()).makeNoise();
}
or
#Test
public void shouldDoNotMakeNoisesOnMonday() {
//given
Elephant elephant = spy(new Elephant("foo"));
//when
elephant.perform("monday");
then(elephant).should(never()).makeNoise();
}
Dependency
org.mockito:mockito-core:2.21.0
Read about
Mockito#doNothing()
Mockito#spy(T)
void() functions change the state of a program. This can be done by modifying a variable, a file, a database, etc.
In your case you're writing to a logger. If this results in writing " Elephant make Sound" to a file then you can read that file and see if the data in the file includes your noisy elephant.
If it however doesn't involve anything you can check (i.e.: it simply displays the output on the console) then you might want to look at some form of dependency injection (DI) where you can set the output to a file or something else you can easily read.
It should be noted that you can bypass DI by mocking the object and checking the appropriate methods are getting called.
To test any method, the responsibility to be tested must be visible from the out side of the method by changing state of any variable.
Typically it is done by returning value from the method. But without that, it can be done in many ways by modifying something from outside of the method scope, in case you have any "problem" to return something from the method!
In your case, you only log some message. And your code is not really testable in a sense that it does not do something that is directly related to changing the state of any variable (Because you change the state of other resource other than variable, that is not directly accessible by your code. You have to write some code to read the changes from that external resource, hence makes your testing code dependent to the reading also. If you have some problem with reading, your test case will not pass and that does not go with the spirit of the unit testing. The main idea is to reduce the dependency on external codes or libraries as much as possible). But your code can be testable by doing a slight refactoring / shifting responsiblity like below:
String makeNoise() {
return "Elephant make Sound";
}
String perform(String day) {
if (day.equals("thursday") || day.equals("friday")) {
return makeNoise();
}
}
And then you shift the responsibility of logging the value returned from perform method to the one using it like below:
logger.info(perform(day));
You have various options depending on the tools you are willing to use and the depth your tests should have.
Partial Mocking with plain Java
Create a class (MockElephant) that extends from elephant, overwrite makeNoise so it counts the number of invocations. Use that class in your test to check that makeNoise was called the correct number of times
Partial Mocking with a Framework
You basically do the same as above but instead of manually coding the MockElephant you create it using some mocking framework. Makes the test much simpler, since you need less code. And it is easier to read. But if strange things happen it makes it harder to understand what is going on. In case of Mocking frameworks I think they are worth it.
The reasons why this is called Partial Mocking is that you mock only parts of a class (a single method in this case).
The alternative is to use Normal Mocks, which in your case seems feasible (but can become tough in legacy code).
Here you would inject the Logger as a dependency. For example you could create an additional constructor which allows you to provide the Logger. In your test you would then use a mocked Logger, which again counts it's invocations, probably along with the parameter it received and check that it has the expected values.
Again you can do that with a Mocking Framework or with plain old Java.
I have an existing class into which I want to add a method. But I want the method to be called only from a specific method from a specific class. Is there any way that I can prevent that call from other classes/methods?
For example, I have an existing class A
public final class A
{
//other stuff available for all classes/methods
//I want to add a method that does its job only if called from a specific method of a class, for example:
public void method()
{
//proceed if called from Class B.anotherMethod() else throw Exception
}
}
One way of doing this is getting the StackTrace inside the method() and then confirming the parent method?
What I am looking for is a solution that is more clean and advisable solution like a pattern or something.
To be honest, you have painted yourself into a corner here.
If classes A and B are not related and not members of the same package, then visibility won't solve the problem. (And even if it did, reflection can be used to subvert the visibility rules.)
Static code analysis won't solve the problem if the code can use reflection to call the method.
Passing and checking B.this as an extra parameter to A.method(...) doesn't help because some other class C could pass a B instance.
This leaves only the stacktrace approach1... or giving up and relying on the good sense of the programmer2 not to call methods that they shouldn't.
The ideal solution is to revisit the design and/or coding decisions that got you into this mess.
1 - See other answers for examples that use annotations, a security manager, etc to conceal the stacktrace stuff from the application programmer. But note that under the hood you are adding probably hundreds, possibly thousands of instructions overhead per method call.
2 - Do not underestimate the programmer's good sense. Most programmers, when they see advice not to call some method, are likely to follow that advice.
The right way to do this would be a SecurityManager.
Define a permission which all code which wants to call A.method() has to have, and then make sure only B and A have that permission (this also means that no class has AllPermission).
In A, you check this with System.getSecurityManager().checkPermission(new BMethodPermission()), and in B you call the method inside of AccessController.doPrivileged(...).
Of course, this requires that a security manager is installed (and it uses suitable policies) - if it isn't, all code is trusted and everyone can call everything (if necessary, with Reflection).
You might consider using an interface. If you're passing in the calling class, you can confirm that the class is of the appropriate type.
Alternatively, if you're using Java, you can use "default" or "package" level access (e.g. void method() vs. public void method()). This will allow your method to be called by any class inside the package and does not require that you pass the class to the method.
The only way to check for sure at run time is to take a stack trace. Even if its private you can access the method via reflections.
A simpler way to do this would be to check usages in your IDE. (provided its not called via reflections)
As others have mentioned, using the stack trace is one way to implement the functionality that you are looking for. Generally, if one needs to "block" callers from a public method, it could be a sign of poor design. As a rule of thumb, use access modifiers that restrict the scope as much as possible. However, making a method package-private or protected is not always an option. Sometimes, one may want to group some classes in a separate package. In that case, the default (package-private) access is too restrictive, and it usually does not make sense to subclass, so protected is not helpful either.
If restricting calling to certain classes is desired, you can create a method like:
public static void checkPermission(Class... expectedCallerClasses) {
StackTraceElement callerTrace = Thread.currentThread().getStackTrace()[3];
for (Class expectedClass : expectedCallerClasses) {
if (callerTrace.getClassName().equals(expectedClass.getName())) {
return;
}
}
throw new RuntimeException("Bad caller.");
}
Using it is very simple: just specify what class(es) can call the method. For example,
public void stop() {
checkPermission(ShutdownHandler.class);
running = false;
}
So, if the stop method gets called by a class other than ShutdownHandler, checkPermission will throw an IllegalStateException.
You may wonder why checkPermission is hard-coded to use the fourth element of the stack trace. This is because Thread#getStackTrace() makes the most recently called method the first element. So,
getStackTrace()[0] would be the call to getStackTrace itself.
getStackTrace()[1] would be the call to checkPermission.
getStackTrace()[2] would be the call to stop.
getStackTrace()[3] would be the method that called stop. This is what we are interested in.
You mentioned that you want methods to be called from a specific class and method, but checkPermission only checks for class names. Adding the functionality to check for method names requires only a few modifications, so I'm going to leave that as an exercise.
Make proper use of protected
The standard way to do this in java is to put Class B and Class A in the same package (maybe a subpackage of your current application) and use the default visibility.
The default java visibility is "package-private" which means everything in that package can see your method, but nothing outside that package can access it.
See Also:
Is there a way to simulate the C++ 'friend' concept in Java?
Assuming that you only need to apply this restriction to classes within your project, static analysis could work for you - for example an ArchUnit test:
package net.openid.conformance.archunit;
import com.google.gson.JsonElement;
import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.AccessTarget;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.lang.ArchRule;
import net.openid.conformance.testmodule.OIDFJSON;
import org.junit.Test;
import static com.tngtech.archunit.core.domain.JavaCall.Predicates.target;
import static com.tngtech.archunit.core.domain.JavaClass.Predicates.assignableTo;
import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.*;
import static com.tngtech.archunit.core.domain.properties.HasOwner.Predicates.With.owner;
import static com.tngtech.archunit.lang.conditions.ArchPredicates.are;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
public class PreventGetAs {
#Test
public void doNotCallJsonElementGetAs() {
JavaClasses importedClasses = new ClassFileImporter().importPackages("net.openid.conformance");
JavaClasses allExceptOIDFJSON = importedClasses.that(DescribedPredicate.not(nameContaining("OIDFJSON")));
ArchRule rule = noClasses().should().callMethodWhere(
target(nameMatching("getAs[^J].*")) // ignores getAsJsonObject/getAsJsonPrimitive/etc which are fine
.and(target(owner(assignableTo(JsonElement.class)))
)).because("the getAs methods perform implicit conversions that might not be desirable - use OIDFJSON wrapper instead");
rule.check(allExceptOIDFJSON);
}
}
You can do it by using annotations and reflection. I will report a similar case, i.e. the case where you can let the method being called only by specific methods from extenal classes. Suppose that the class that must be "protected" by a whatsoever invocation of the its public methods is Invoked, while Invoker is the class tha has a method enabled to invoke one or more methods from Invoked. Then, you can do something like reported in the following.
public class Invoked{
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public static #interface CanInvoke{}
public void methodToBeInvoked() {
boolean canExecute=false;
try {
//get the caller class
StackTraceElement element = (new Throwable()).getStackTrace()[1];
String className = element.getClassName();
Class<?> callerClass = Class.forName(className);
//check if caller method is annotated
for (Method m : callerClass.getDeclaredMethods()) {
if (m.getName().equals(methodName)) {
if(Objects.nonNull(m.getAnnotation(EnabledToMakeOperationRemoved.class))){
canExecute = true;
break;
}
}
}
} catch (SecurityException | ClassNotFoundException ex e) {
//In my case does nothing
}
if(canExecute){
//do something
}
else{
//throw exception
}
}
}
and the Invoker class is
public class Invoker{
private Invoked i;
#Invoked.CanInvoke
public void methodInvoker(){
i.methodToBeInvoked();
}
}
Note that the method that is enabled to invoke is annotated with the CanInvoke annotation.
The case that you requested is similar. You annotate the classes/method that cannot call the public method and then you set to true the canExecute variable only if the method/class is not annotated.
You can use a tool like Macker and add it to your build process to check some rules are respected, like
<?xml version="1.0"?>
<macker>
<ruleset name="Simple example">
<access-rule>
<deny>
<from class="**Print*" />
<to class="java.**" />
</deny>
</access-rule>
</ruleset>
</macker>
It will NOT prevent you from writing wrong code but if you use Maven or another build system it can raise an error during your build process.
This tools work at a "class" level not at a "method" level but I do not see the point of preventing the call of only one method from a certain class ...
I realise your use case states 'specific method in specific class', but I don't think you can reliably solve this at design time (and I can't think of a use case where this would have to be enforced anyway).
The following example creates an easy design time solution for restricting the access of a class' method to a particular class. It can, however, be easily extended to multiple allowed classes.
It is achieved by defining a public inner class with a private constructor that acts as a key to the method at hand. In the following example the class Bar has a method that should only be called from an instance of the Foo class.
Class Foo:
public class Foo
{
public Foo()
{
Bar bar = new Bar();
bar.method(new FooPrivateKey());
}
public class FooPrivateKey
{
private FooPrivateKey()
{ }
}
}
Class Bar:
public class Bar
{
public Bar()
{
}
public void method(FooPrivateKey fooPrivateKey)
{
if(fooPrivateKey == null)
{ throw new IllegalArgumentException("This method should only be called from the Foo class.");}
//Do originally intended work.
}
}
I don't think this is by any means safe for things like reflection or even things like FooPrivateKey.class.newInstance(), but this will at least warn the programmer a little more obtrusively than a simple comment or documentation, while you don't have to look in to more complicated things like what was suggested by people like Roberto Trunfio and Ronan Quillevere (which are perfectly viable answers as well, just too complicated for most situations in my opinion).
I hope this is sufficient for your use case.
I have long java class and method names
LONGGGGGGGGGGGGGGGClass.longggggggggggggggggggggggggMethod();
I want to alias it to
g.m(); in another class
can this be done?
No.
Wrap it in a method with a name you like better.
For one thing, you should rarely be typing the class name. You might have something like this:
import DamnLongPackageNameThatIDontLikeTyping;
class MyCoolClass()
{
DamnLongClassNameThatIDontLikeTyping dlc=new DamnLongClassNameThatIDontLikeTyping();
dlc.this();
dlc.that();
dlc.tOther();
dlc.damnLongAnnoyingMethodNameStillHasToBeTypedEveryTime();
}
Okay, so that's not great, but you shouldn't be typing the entire class name very often, just when you first declare it; and the package import makes it so you don't have to type: DamnLongPackageNameThatIDontLikeTyping.DamnLongClassNameThatIDontLikeTyping every time.
Still, that can be annoying to type. Enter the editor. If you aren't using Eclipse, Netbeans or IntelliJ then you really need to stop reading right now and go install it--load up your project. I'll wait....
Seriously. Go get it. The rest of this won't be any fun without it.
Now, the really neat thing is that to get what I typed above, you just do this:
class MyCoolClass()
{
DLC<ctrl-space>
After typing that, your file will look like this:
import DamnLongPackageNameThatIDontLikeTyping;
class MyCoolClass()
{
DamnLongClassNameThatIDontLikeTyping<your cursor here>
Note that you didn't type damn long ANYTHING, just DLC It figured out what class you wanted to import, added an import for it and stuck the class in there. (You may have to choose from a list of classes if there is more than one match).
On top of that, once you have an object named dlc instantiated you can type:
dlc.<ctrl-space> and get a list of methods in that class. NEVER AGAIN TYPE A METHOD NAME. If there are a kagillion methods in your class, don't scroll over them, type: dlc.dLAM<ctrl-space> to get dlc.damnLongAnnoyingMethodNameStillHasToBeTypedEveryTime();
Never type a long method name again.
No long method names, no long class names, no long package names. Yet you get extremely readable methods, packages and classes. This is why java programmers tend to use these long names, we also try to remember that we are coding for the next guy and don't want him to have to run all over our code trying to figure out what:
g.m(); refers to -- forcing them to remember that in this class it means GreatClass.motion, but in the next class it means Grey.modifyColor -- that would be really cruel.
Java being statically typed places a LOT of power into the editor. It can do things that you can't even dream of doing with dynamically typed languages, and you should play to the strength of your language to be an effective programmer -- not try to fit each language into some style you learned from using another language.
Note that this works for static methods as well...
DLC<ctrl-space>.dLM<ctrl-space> would be replaced by a call to DamnLongClass.damnLongMethod(), and it would even include the parens for you in 9 keystrokes.
The Java language provides no aliasing mechanism.
However, you could ease your "pain" somewhat by some combination of the following:
For static methods, you can use static imports to avoid having the long class name.
You could declare your own convenience class with a short name and short method names, and implement the static methods to delegate to the real methods like:
public static void shortName(...) {
VeryLongClassName.veryLongMethodName(...);
}
For regular methods, you could implement a Wrapper class, or a subclass with more convenient method names. However, both have downsides from the maintenance and (depending on your JVM) performance perspectives.
In Java 8 and later, you could potentially take a method reference, assign it to a named variable, and use that to make your calls.
But lets step back:
If the real problem is that you are just fed up with typing long names, a solution is to use a modern IDE that supports completion of names as you type them. See #BillK's answer for example.
If the real problem is that you are fed up with the long names taking to much space, a solution is to use a wider screen / longer lines. Most monitors are big enough to display 120 character (or more) wide source code with no eye strain.
If neither of the above is the answer, consider just refactoring the offending code to use sensible (i.e. shorter) class and method names. Once again, a modern IDE can handle this kind of refactoring quickly and safely.
On the last point, I would consider that the overly long class names and method names are bad style. IMO, you are justified in taking the time to fix them yourself, or suggesting that they be fixed, especially if they constitute a "public" API for some library or module.
To those who would argue that long identifiers are good style because they convey more information, the counter argument is that they don't actually improve readability. But if you say that they do improve readability, then it follows that using aliases instead of the long identifiers would be reducing readability!
Actually there is a way to get 1/2 of what you're after.
Looking at your example:
LONGGGGGGGGGGGGGGGClass.longggggggggggggggggggggggggMethod();
It appears that longggggggggggggggggggggggggMethod is static. (If it weren't, you'd be prefixing it with a variable name, which you control the size of.)
You can use Java's static import feature to 'alias' or import the static methods of the LONGGGGGGGGGGGGGGGClass into your own class' namespace. Instead of the above code, you would only have to write this:
longggggggggggggggggggggggggMethod();
You can use inheritance or encapsulation to wrap the original class.
class g extends LONGCLASS
{
void a() { super.loooonnng(); }
}
or
class g
{
private LONGCLASS lc;
void a() { lc.loooonnng(); }
}
Not supported in Java.
There is an enhancement ticket (7166917) for adding aliases for imports which would be helpful. The idea is this :
import a.very.lng.pckage.* as shortpckg
import my.pckage.IsAVeryLongClassName as MyShort
public class Shorten
{
public static final Shorten m = new Shorten();
public int a(params)
{
return some_method_with_long_name(params);
}
public void b()
{
// whatever static code you want
}
}
In your main code then:
import static mypackage.Shorten.m;
...
int res = m.a(params);
m.b();
...
This way you effectively alias any static stuff you want, while avoiding warnings.
I only ran a simple test but I defined an inner class variable. I'm not an expert nor do I know the consequences of doing this but I obtained positive results.
package a.b;
public class Library {
public static String str;
}
Now write a class to access the static variables from Library
package a.b;
public class Access {
public class Short extends Library {}
Short.str;
}
I'm sure you all know the behaviour I mean - code such as:
Thread thread = new Thread();
int activeCount = thread.activeCount();
provokes a compiler warning. Why isn't it an error?
EDIT:
To be clear: question has nothing to do with Threads. I realise Thread examples are often given when discussing this because of the potential to really mess things up with them. But really the problem is that such usage is always nonsense and you can't (competently) write such a call and mean it. Any example of this type of method call would be barmy. Here's another:
String hello = "hello";
String number123AsString = hello.valueOf(123);
Which makes it look as if each String instance comes with a "String valueOf(int i)" method.
Basically I believe the Java designers made a mistake when they designed the language, and it's too late to fix it due to the compatibility issues involved. Yes, it can lead to very misleading code. Yes, you should avoid it. Yes, you should make sure your IDE is configured to treat it as an error, IMO. Should you ever design a language yourself, bear it in mind as an example of the kind of thing to avoid :)
Just to respond to DJClayworth's point, here's what's allowed in C#:
public class Foo
{
public static void Bar()
{
}
}
public class Abc
{
public void Test()
{
// Static methods in the same class and base classes
// (and outer classes) are available, with no
// qualification
Def();
// Static methods in other classes are available via
// the class name
Foo.Bar();
Abc abc = new Abc();
// This would *not* be legal. It being legal has no benefit,
// and just allows misleading code
// abc.Def();
}
public static void Def()
{
}
}
Why do I think it's misleading? Because if I look at code someVariable.SomeMethod() I expect it to use the value of someVariable. If SomeMethod() is a static method, that expectation is invalid; the code is tricking me. How can that possibly be a good thing?
Bizarrely enough, Java won't let you use a potentially uninitialized variable to call a static method, despite the fact that the only information it's going to use is the declared type of the variable. It's an inconsistent and unhelpful mess. Why allow it?
EDIT: This edit is a response to Clayton's answer, which claims it allows inheritance for static methods. It doesn't. Static methods just aren't polymorphic. Here's a short but complete program to demonstrate that:
class Base
{
static void foo()
{
System.out.println("Base.foo()");
}
}
class Derived extends Base
{
static void foo()
{
System.out.println("Derived.foo()");
}
}
public class Test
{
public static void main(String[] args)
{
Base b = new Derived();
b.foo(); // Prints "Base.foo()"
b = null;
b.foo(); // Still prints "Base.foo()"
}
}
As you can see, the execution-time value of b is completely ignored.
Why should it be an error? The instance has access to all the static methods. The static methods can't change the state of the instance (trying to is a compile error).
The problem with the well-known example that you give is very specific to threads, not static method calls. It looks as though you're getting the activeCount() for the thread referred to by thread, but you're really getting the count for the calling thread. This is a logical error that you as a programmer are making. Issuing a warning is the appropriate thing for the compiler to do in this case. It's up to you to heed the warning and fix your code.
EDIT: I realize that the syntax of the language is what's allowing you to write misleading code, but remember that the compiler and its warnings are part of the language too. The language allows you to do something that the compiler considers dubious, but it gives you the warning to make sure you're aware that it could cause problems.
They cannot make it an error anymore, because of all the code that is already out there.
I am with you on that it should be an error.
Maybe there should be an option/profile for the compiler to upgrade some warnings to errors.
Update: When they introduced the assert keyword in 1.4, which has similar potential compatibility issues with old code, they made it available only if you explicitly set the source mode to "1.4". I suppose one could make a it an error in a new source mode "java 7". But I doubt they would do it, considering that all the hassle it would cause. As others have pointed out, it is not strictly necessary to prevent you from writing confusing code. And language changes to Java should be limited to the strictly necessary at this point.
Short answer - the language allows it, so its not an error.
The really important thing, from the compiler's perspective, is that it be able to resolve symbols. In the case of a static method, it needs to know what class to look in for it -- since it's not associated with any particular object. Java's designers obviously decided that since they could determine the class of an object, they could also resolve the class of any static method for that object from any instance of the object. They choose to allow this -- swayed, perhaps, by #TofuBeer's observation -- to give the programmer some convenience. Other language designers have made different choices. I probably would have fallen into the latter camp, but it's not that big of a deal to me. I probably would allow the usage that #TofuBeer mentions, but having allowed it my position on not allowing access from an instance variable is less tenable.
Likely for the same logical that makes this not an error:
public class X
{
public static void foo()
{
}
public void bar()
{
foo(); // no need to do X.foo();
}
}
It isn't an error because it's part of the spec, but you're obviously asking about the rationale, which we can all guess at.
My guess is that the source of this is actually to allow a method in a class to invoke a static method in the same class without the hassle. Since calling x() is legal (even without the self class name), calling this.x() should be legal as well, and therefore calling via any object was made legal as well.
This also helps encourage users to turn private functions into static if they don't change the state.
Besides, compilers generally try to avoid declaring errors when there is no way that this could lead to a direct error. Since a static method does not change the state or care about the invoking object, it does not cause an actual error (just confusion) to allow this. A warning suffices.
The purpose of the instance variable reference is only to supply the type which encloses the static. If you look at the byte code invoking a static via instance.staticMethod or EnclosingClass.staticMethod produces the same invoke static method bytecode. No reference to the instance appears.
The answer as too why it's in there, well it just is. As long as you use the class. and not via an instance you will help avoid confusion in the future.
Probably you can change it in your IDE (in Eclipse Preferences -> Java -> Compiler -> Errors/Warnings)
There's not option for it. In java (like many other lang.) you can have access to all static members of a class through its class name or instance object of that class. That would be up to you and your case and software solution which one you should use that gives you more readability.
It's pretty old topic but still up-to-date and surprisingly bringing higher impact nowadays. As Jon mentioned, it might be just a mistake Java's designers made at the very beginning. But I wouldn't imagine before it can have impact on security.
Many coders know Apache Velocity, flexible and powerful template engine. It's so powerful that it allows to feed template with a set of named objects - stricly considered as objects from programming language (Java originally). Those objects can be accessed from within template like in programming language so for example Java's String instance can be used with all its public fields, properties and methods
$input.isEmpty()
where input is a String, runs directly through JVM and returns true or false to Velocity parser's output). So far so good.
But in Java all objects inherit from Object so our end-users can also put this to the template
$input.getClass()
to get an instance of String Class.
And with this reference they can also call a static method forName(String) on this
$input.getClass().forName("java.io.FileDescriptor")
use any class name and use it to whatever web server's account can do (deface, steal DB content, inspect config files, ...)
This exploit is somehow (in specific context) described here: https://github.com/veracode-research/solr-injection#7-cve-2019-17558-rce-via-velocity-template-by-_s00py
It wouldn't be possible if calling static methods from reference to the instance of class was prohibited.
I'm not saying that a particular programming framework is better than the other one or so but I just want to put a comparison. There's a port of Apache Velocity for .NET. In C# it's not possible to call static methods just from instance's reference what makes exploit like this useless:
$input.GetType().GetType("System.IO.FileStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
I just consider this:
instanceVar.staticMethod();
to be shorthand for this:
instanceVar.getClass().staticMethod();
If you always had to do this:
SomeClass.staticMethod();
then you wouldn't be able to leverage inheritance for static methods.
That is, by calling the static method via the instance you don't need to know what concrete class the instance is at compile time, only that it implements staticMethod() somewhere along the inheritance chain.
EDIT: This answer is wrong. See comments for details.