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.
Related
This question already has answers here:
Why is an anonymous inner class containing nothing generated from this code?
(5 answers)
Closed 7 years ago.
In the below code :
class EnclosingClass
{
public static class BiNode extends Sub.IBiLink { }
private static class Sub
{
private static class IBiLink
{
}
}
}
On compiling along with other .class files, I also see a file named "EnclosingClass$1.class" .Why has this been automatically created? Whats going on?
First have a look at the class access and propery modifier table from the JVM specifications.
Notice the ACC_SYNTHETIC flag which interpretation specify that it is not present in the source code (in simplier words, it will be added when the class is generated by the compiler).
Let's have a look at the bytecode of EnclosingClass$1.class (note that I will paste only the part that matter).
javap -v EnclosingClass$1.class
produce the following result
Classfile /C:/Users/jfrancoiss/Desktop/Nouveau dossier/EnclosingClass$1.class
Last modified 2015-03-31; size 190 bytes
MD5 checksum 5875440f1e7f5ea9a519d02fbec6dc8f
Compiled from "EnclosingClass.java"
class EnclosingClass$1
minor version: 0
major version: 52
flags: ACC_SUPER, ACC_SYNTHETIC
Notice that the access flags of the class contains ACC_SYNTHETIC.
The ACC_SYNTHETIC flag indicates that this class or interface was
generated by a compiler and does not appear in source code.
An other option to make sure the generated class is synthetic is to compile as
javac -XD-printflat EnclosingClass.java
which would produce
/*synthetic*/ class EnclosingClass$1 {
}
Great, but why generate a synthetic class ?
The Java reflection tutorial can help us understand this. Have a look at the comments in the SyntheticConstructor class
public class SyntheticConstructor {
private SyntheticConstructor() {}
class Inner {
// Compiler will generate a synthetic constructor since
// SyntheticConstructor() is private.
Inner() { new SyntheticConstructor(); }
}
}
So according on the comment, the synthetic class EnclosingClass$1.class was created because IBiLink was private.
Once again, the java reflection tutorial specify at this point
Since the inner class's constructor references the private constructor
of the enclosing class, the compiler must generate a package-private
constructor.
In our case, we do not see explicitely any constructor call, but we have this line
public static class BiNode extends Sub.IBiLink { }
Let's try compiling this code and see what happen
class EnclosingClass
{
//public static class BiNode extends Sub.IBiLink { }
private static class Sub
{
private static class IBiLink
{
}
}
}
No EnclosingClass$1.class generated.
More details noticed when debugging
Change
private static class IBiLink
to
protected static class IBiLink
notice that when compiling, EnclosingClass$1.class is not created.
why does protecting the class did not generate a synthetic class ?
Simply because when protecting the class, you implicitely get access to each of the super classes.
Why don't eclipse compiler generate a synthetic class ?
Eclipse use it built-in compiler, which you can configure it severity level.
By default, Access to a non-accessible member of an enclosing type is set to ignore as you can see on this image.
Change it for example to warning and you will get the following message.
which let me believe that eclipse, altought does not create an other class, will emulate it to simulate the synthetic member.
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.
I'm studying for Java SE 7 certification exam and I'm doing some boring excercises about inheritance and access modifiers.
But now I'm getting an unexpected behavior applying inheritance. In my base package com.testpkg I have an abstract class:
package com.testpkg;
public abstract class Abstract {
public int test();
}
NOTE that I voluntarily omitted the abstract modifier for the test() method.
Then I have a concrete class extending Abstract in package com.testpkg.sub:
package com.testpkg.sub;
public class Concrete extends Abstract {
public int test() {
return 0;
}
}
I test this classes using:
package com.testpkg;
import com.testpkg.sub.Concrete;
public class TestMain {
public static void main(String[] args) {
Abstract c = new Concrete();
System.out.println(c.test());
}
}
If I try to compile this, I obviously get two errors:
The method test() requires a body instead of a semicolon
But if I run test class: 0 is printed on console!
This seems very strange to me. Can you explain why the code is working even test() is wrongly declared in Abstract class?
NOTE I'm using Eclipse IDE to compile/run my code.
You need an abstract qualifier on your test() method. You're likely running an old class file. If you change the value of your return statement to something besides 0, you will see that it isn't running this code.
Eclipse allows you to run "half baked" code. The reason why it runs fine here is because, at runtime, you never really depend on the specifics of the Abstract class so it doesn't really matter if you have this type of compile error in it.
Yours class Abstract has compilation errors, because non abstract method should be defined, so it should have a body. abstract qualifier is optional only in case of interfaces.
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
}
}
I'm working on a project which has both scala and java code. I want to use a class written in scala in java code. Problem I'm having is that scala class has some self type dependencies. I don't know how to give them when creating new instance of that class from java.
trait Deps1 {
def dep1 = println("dep1")
}
trait Deps2 {
def dep2 = println("dep2")
}
class TestClass {
this: Deps1 with Deps2 =>
def test = {
dep1
dep2
}
}
In scala if I'm to create instance of TestClass I can use new TestClass with Deps1 with Deps2 but I don't know how to do that in java code.
I'm using scala 2.9.2. Can anyone help me on this?
If the traits are at all complicated, it's best to let Scala handle them. Write a stub in Scala that the Java can instantitate:
class TestWithDeps extends TestClass with Deps1 with Deps2
Scala traits are compiled to Java interfaces. So, in your Java code you are implementing the interface Deps1 for example. See this answer for example and details
For your code the the following Java code works:
class Test extends TestClass implements Deps1, Deps2{
public void dep1(){
Deps1$class.dep1(this);
}
public void dep2(){
Deps2$class.dep2(this);
}
public static void main(String []args){
Test test = new Test();
test.dep1();
test.dep2();
}
}
Running this gives:
dep1
dep2
Compile and run with the compiled Deps1, Deps2, and TestClass on the classpath and the scala-library jar like so javac -classpath .:scala-library.jar Test.java
You are asking on how to create anonymous classes in Java mixing traits. This is simply not possible because in Java you cannot mix a trait, you can implement an interface, which contains no code.
If you reason a little bit about the concept of Scala Trait and how it could be implemented on the top of JVM valid bytecote keeping the compatibility with Java, you figure it out by yourself (I am not saying this this the exact way Scala treats traits, but is very similar)
A java interface is created
When the trait is mixed into a class, at compile time the "concrete" functions are physically copied by the compiler into the class.
This is the trick that allows Scala trait to contain concrete functions, but of course you need the source file to be a Scala one. Remember furthermore that when you create anonymous classes like :
val a = new MyClass extends A with B
The scala compiler physically generates an anonymous class for that (and apply the necessary transformation to mix traits). So, if you need to create an instance of MyClass extends A with B from Java, as Rex suggested the best way is to create a stub in Scala, and instanciate that from Java. The stub will be compiled by Scalac, which will correctly handle trait.