Not able to use methods generated by groovy #Delegate from java classes - java

when running the code below
i'm getting compilation error:
java: ..\JavaClass.java:8: cannot find symbol
symbol : method add(java.math.BigDecimal)
location: class BigDecimalDelegated
it seems like the stub of the groovy class created for the java compiler does not contain the delegated methods.
any idea?
consider this classes:
class BigDecimalDelegated //groovy class
{
#Delegate BigDecimal delegated;
String data;
}
import org.junit.Test;
import java.math.BigDecimal;
public class JavaClass //java class
{
#Test
public void temp()throws Exception
{
new BigDecimalDelegated().add(BigDecimal.TEN);
}
}

Groovy compiler used in IDEA's external build doesn't support this, see https://issues.apache.org/jira/browse/GROOVY-4647
You can either use #Delegate classes from Groovy code only, or switch off external build in Settings | Compiler to use the old build mechanism.

How are you running/compiling the code?
Also, I believe you'll need to set delegated in the constructor for BigDecimalDelegated
class BigDecimalDelegated //groovy class
{
#Delegate BigDecimal delegated
String data
BigDecimalDelegated() {
delegated = 0.0G
}
}

Related

Java Junit4 Supporting extended base class

a question:
When I do something like:
package path.to.common.package.test;
#BeforeClass
public class CommonTestSetup {
public void setUp() {
// Setup Stiff
}
}
And the other class setup in the same package:
package path.to.common.package.test;
public class TestTest extends CommonTestSetup {
#Test
public void testGetTestReturnsCorrectStrings() {
// do asserts etc
}
}
And then executing JUnit test on testGetTestReturnsCorrectStrings I am getting an error:
org.junit.runners.model.InvalidTestClassError: Invalid test class 'org.junit.runner.manipulation.Filter':
1. No runnable methods
at org.junit.runners.ParentRunner.validate(ParentRunner.java:456)
at org.junit.runners.ParentRunner.<init>(ParentRunner.java:99)
at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:84)
at org.junit.runners.JUnit4.<init>(JUnit4.java:23)
at org.junit.internal.builders.JUnit4Builder.runnerForClass(JUnit4Builder.java:10)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:66)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:37)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:66)
at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:39)
at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:36)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createFilteredTest(JUnit4TestLoader.java:80)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:71)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:46)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:523)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:761)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:461)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:207)
Why is that? Does it mean JUnit 4 does not support Test classes extending a base class?
The idea behind this was to create a single SetUp base class, shared by many other test classes that need it.
Originally I even tried to have the base class in another package entirely, then moved it to the same package for testing, and got a different error (the one above).
use import org.junit.Test;
instead of import org.junit.jupiter.api.Test;
Based on the JUnit documentation:
Annotating a public static void no-arg method with #BeforeClass causes it to be run once before any of the test methods in the class
So move the #BeforeClass annotation to the setUp method and make into a static method.
You may also check for things like
class classname {
class another class{
}
}
Keep one class in file it helps
I experienced similar ... I hopes it help someone ;-)

Why prefer the indirect generic's import to the actual class?

Using eclipse if I write this interface in the package mypack:
package mypack;
public interface MyInterface<A>{
public interface Test{
void sayHi();
}
}
And if I write this class in no package.
public class Test implements mypack.MyInterface<mypack.MyInterface.Test> {
private Test test = new Test();
}
Eclipse trigger me an error at compile-time, that I must implement the method sayHi().
I see no way out!
If I Ctrl+LMB to the type of the field test it takes me to the Class.
Bug reported
A small bug is reported here: https://bugs.eclipse.org/bugs/show_bug.cgi?id=488077
What is happening here is
Test test = new Test();
the Test is being taken as a nested-type of the MyInterface you inherit from.
I will look into the JLS to see if there is a reason it chooses the inherited class over it's own name.
Note: MyInterface doesn't have to be generic. A simpler form of this problem is
interface MyInterface {
interface Test {
}
}
class Test extends MyInterface {
Test test = new Test(); // thinks this is the MyInterface.Test
}
BTW: As this is very confusion combination of class structure and names, I suggest you never do this in reality.
A note from JLS 7.4.2
Unnamed packages are provided by the Java SE platform principally for convenience when developing small or temporary applications or when just beginning development.

How to give warning message in own API?

Is that possible to give custom warning message in my own API like below? Is Resource leak:'ois' is never closed message related with Java API or JVM?
It's possible using a compiler API. You have to extend an AbstractProcessor and then make sure compiler knows about it.
Lets say we don't like programmers to swear in the source code. So, when someone defines a field with name "shit", we want to show a warning. Here is a simple implementation:
import java.util.List;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
#SupportedSourceVersion(SourceVersion.RELEASE_7)
#SupportedAnnotationTypes("*")
public class Test extends AbstractProcessor {
public int shit;
public int foo;
#Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
Set<? extends Element> rootElements = roundEnv.getRootElements();
for (Element element : rootElements) {
if (element.getKind() == ElementKind.CLASS) {
List<? extends Element> classElements = element.getEnclosedElements();
for (Element classElement : classElements) {
if (classElement.getKind() == ElementKind.FIELD) {
if (classElement.getSimpleName().contentEquals("shit")) {
processingEnv.getMessager().printMessage(
Kind.WARNING,
"How dare you to swear in the source code?!",
classElement
);
}
}
}
}
}
return false;
}
public static void main(String[] args) {
//
}
}
Now, we want to apply such a processor just for this very class, because there is an ugly bad-called field too.
Using a command line:
javac Test.java
javac -processor Test Test.java
We need to firstly build a processor and then apply it while compiling (in this case to the same file).
And this is the output we get:
Test.java:17: warning: How dare you to swear in the source code?!
public int shit;
^
1 warning
To have the same warning in Eclipse or any other IDE, it's necessary to change compiler settings so it uses this custom processor.
Update: In the comments, kapep sent a link on how to set a custom processor in Eclipse: http://kerebus.com/2011/02/using-java-6-processors-in-eclipse/
Just for the record: Exactly the same warning may be achieved by implementing interface Closeable:
import java.io.Closeable;
import java.io.IOException;
public class Test implements Closeable {
#Override
public void close() throws IOException {
// TODO Auto-generated method stub
}
public static void main(String[] args) {
new Test();
}
}
And you see the same warning:
You can create warnings, notes, errors and other diagnostic messages like this using an annotation processor. It's a compiler plugin api integrated in the JDK. It lets you analyse the outline structure of source code. Despite the name you don't really need to handle any annotation when processing code. Messages are created using the Messager class. If you provide an element, it will be marked and the message will be shown next to it in the source code editor.
You won't be able to show message on elements inside methods or expressions though, only on declarations like types, properties, methods or parameters. It's possible to additionally parse the method body and generate messages based on the content using other tools, but as far as I know you can't show the message on the actual local element then. You could still show the message on the enclosing method or don't specify any element at all and show it in the IDE's log.
The IDE also needs to support this. I know that Eclipse and NetBeans do support messages generated by annotation processors, but there are probably other modern IDE that do so as well. If you need more features like messages on elements inside method bodies or the quick fix feature as shown in the example, I guess you need to create a plugin for the IDE.
I would believe that it is related to the eclipse ide, you could possibly write a plugin which displays warnings like that.
For example, when you use a method which has the annotation '#Deprecated' the ide automatically tells the programmer that the method is deprecated.

Instantiating Groovy class within Java class

I have a groovy class
#Immutable
class StatusCode {
final int statusCode
}
I want to create an object of this class in another Java class say, Test.Java. But when I use,
public class Test{
StatusCode statusCode;
public void setStatusCode(int statusCode)
{
this.statusCode = new StatusCode(statusCode);
}
}
It says the constructor is missing. How do I instantiate this object ?
Groovy code can be compiled into Java bytecode using groovyc. This will give you a valid Java class you can reference from any other Java class. You do still need to have the groovy runtime JAR on your claspath.
It's possible the Groovy compiler will generate the desired constructor for you, but I'm not sure. If not, you'd need to explicitly code it in the Groovy class.

In java how do you refer to a class that is in the default package of a third party library?

I have downloaded a third party library and they have classes I need to refer to in the default package? How do I import these classes?
It's not possible directly with the compiler. Sun removed this capability. If something is in the default namespace, everything must be in the default namespace.
However, you can do it using the ClassLoader. Assuming the class is called Thirdparty, and it has a static method call doSomething(), you can execute it like this:
Class clazz = ClassLoader.getSystemClassLoader().loadClass("Thirdparty");
java.lang.reflect.Method method = clazz.getMethod("doSomething");
method.invoke(null);
This is tedious to say the least...
Long ago, sometime before Java 1.5, you used to be able to import Thirdparty; (a class from the unnamed/default namespace), but no longer. See this Java bug report. A bug report asking for a workaround to not being able to use classes from the default namespace suggests to use the JDK 1.3.1 compiler.
To avoid the tedious method.invoke() calls, I adapted the above solution:
Write an interface for the desired functionality in your desired my.package
package my.package;
public interface MyAdaptorInterface{
public void function1();
...
}
Write an adaptor in the default package:
public class MyAdaptor implements my.package.MyAdaptorInterface{
public void function1(){thirdparty.function1();}
...
}
Use ClassLoader/Typecast to access object from my.package
package my.package;
Class clazz = ClassLoader.getSystemClassLoader().loadClass("MyAdaptor");
MyAdaptorInterface myObj = (MyAdaptorInterface)clazz.newInstance();
myObj.function1();

Categories

Resources