Generate inner class - java

my annotation processor reads a class like this:
#Foo
public class Bar (){
}
Now I want to generate an inner class Bar$MyGeneratedClass so that at the end I have a class MyGeneratedClass that to the compiler / jvm looks like this:
public class Bar (){
// Generated by annotation processor
public static class MyGeneratedClass () { ... }
}
Is this possible? I think so, I guess I just have to name the generated class Bar$MyGeneratedClass right?
Does anybody know how to generate such a inner class with java poet?

You can use javapoet to create new classes. It's not possible modify existing class with javapoet.

On jvm level there is no such things as inner classes.
So while compiling both classes (the inner and the outer) are transfomed to simulate that effect.
The inner class gets a constructor parameter. With that parameter you need to pass in an instance of the outer class.
As both class types can access private members package private accessors are created.
Especially the second transformation requires you to change the outer class.

Related

ByteBuddy: How to declare a class with a custom method inside another class

I'm trying to dynamically create a class which extends a class ServerPing, inside this class there is a static class called Serializer, I want to override its method "a" and returns my own JsonElement.
The problem is that I don't know how to edit a static class inside another class using bytebuddy.
Here is what it could look like (but defineClassInside doesn't exist):
Class<?> serverPingSerializerClone = new ByteBuddy()
.subclass(serverPingClass)
.defineClassInside("Serializer",
new ByteBuddy().subclass(ServerPing.Serializer.class)
.method(ElementMatchers.named("a")
.and(ElementMatchers.returns(JsonElement.class)
.and(ElementMatchers.takesArguments(3))))
.intercept(FixedValue.value(exampleResponse))
.make())
.make()
.load(Core.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER).getLoaded();```
At the byte code level, an inner class Bar defined inside Foo is nothing but a class named Foo$Bar with some additional meta data.
You can just treat the inner/nested class like any other class and subclass it. If you need to add inner class meta data, Byte Buddy has DSL steps to edit/add such information, e.g. innerTypeOf.

Java class declaration - having a '.' and static classes

Hi I was looking at this syntax from the Android API and found it a bit weird.
java.lang.Object
↳ android.graphics.BitmapFactory.Options
public static class
BitmapFactory.Options
I have never seen a class with a '.' in the middle of it. Why didn't they just call the class 'BitmapFactoryOptions'?
Then I was confused even more because I saw this code in a book
final BitmapFactory.Options options = new BitmapFactory.Options();
BitmapFactory is static yet we are creating an instance of it?
Adding to #dasblinkenlight answer, the code could look like:
public class BitmapFactory {
public static class Options {
}
}
And that's indeed the case, see source code for BitmapFactory.
They did not name the class with a dot in it (that would be illegal). All they did was adding a static inner class called Options - a member class of the BitmapFactory class.
This is a common way of hiding classes inside their outer classes when the class or an interface in question has no meaning on its own, and must be interpreted only in the context of its outer class.
Of course the solution that you suggested (naming the class BitmapFactoryOptions) is perfectly valid as well. However, it gives a false impression that the class can be useful on its own.
Perhaps the most commonly used example of this is the Map.Entry<K,V> interface: map entries have meaning only when there is a map around them, so the nesting is very useful.
Just like any other class variable and class method, there can be class within a class as well. The following example shows all three kinds of class members accessed using the same syntax.
public class Person{
public static long totalPopulation;
public static void calculateAge(Date dob){
}
public static class Address{
}
}
All of these will be accessed in the same way. i.e.,
Person.totalPopulation = 700_000_0000L;
Person.calculateAge(person.getDOB());
Person.Address address = new Person.Address();

Class definition in java

I'm new to Java and i want a refinement:
First of all,i am not sure if i can have 2 classes in the same file.
My question is what is each class when you see this sequence of code:
class Something {
//code here
} //end of class Something
public class SomethingElse {
//NO code here!!!
public static void main(String[] args) {
//code of main here
}//end of main
}
What's the role of the class Something Else and why there is no code inside?I know that is a very stupid question but there are some details that i don't really get and i want some help...
You can have more than one class per file, but only one class can be public and its name must match the name of the file (e.g. public MyClass in MyClass.java).
The public class of a file will be visible to the outside world, and in particular if the class has a public static main(String[] args) method, it can be used to start an application.
In your case for example, once you have compiled your file using javac, you will get files Something.class and SomethingElse.class.
Using the command java SomethingElse will tell the Java Virtual Machine to do the following:
Find the SomethingElse class, which must be in the SomethingElse.class file
call the main method, matching the signature I pasted above on this class (and putting any given argument in the args array).
You cannot call java Something because the class isn't public and doesn't have a main method. But other classes in your program (and in particular, SomethingElse, can use your Something class).
You can have just one public class per file, and the file must have the same name of the class. But you can have other private classes that just the file class will see. For example:
File Something.java
public class Something {
//Something can access SomethingElse's doSomething method.
private class SomethingElse {
public void doSomething() {
}
}
}
class SomethingToo {
}
File OtherSomething.java
public class OtherSomething {
//OtherSomething cannot access SomethingElse's doSomething method.
//But can access SomethingToo, if they are in the same package
}
You can have multiple classes defined in a same file. However there should only one class defined as public and file name will be that public class name.
In the No code here!!! you can have class variables and methods defined. Your main() is one such example.
In the above file, there are two classes SomethingElse (public) and Something. Now, this is normally done when the non-public class is called internally by the public class. Also, in the above code fragment, SomethingElse seems to be a 'driver' class. In other words, it does not have any functionality/data of its own, but is used to execute (drive) other classes (probably Something in this case)
You can have nested classes, but two separate, public classes are not allowed. Each public class should be in it's own file named the same as the class.
While it's possible to have 2 classes in the same file, its considered bad practice. Besides the decreased readability, it will eventually become difficult to find out where that class declaration actually took place. Plus, if you declare a variable relating to the class, but not the class sharing the .java name, javac will most likely have issues compiling.
If you have to do it, make sure the only place you are using the second class is within the class sharing the .java name. (E.g. only use a Something object within the SomethingElse class). Otherwise, separate all your classes into separate .java files.
Yes, you can have 2 or more classes in single Java file.
The only condition is only one class will contain main method with signature(public static void main(String[] args)).
And only one public class will be there. And with that public class name you can save your file - the file name has to match the name of the public class.

Java inner class with the same name as other top level class

I have question related to Java inner classes.
Is there a way to access top level class A from top level class Main that define inner class A?
Below is sample code demonstrating the problem:
class A { // Outer Class A
{
System.out.println("A outer");
}
}
class B { // Outer Class B
{
System.out.println("B outer");
}
}
public class Main {
class A { // Inner Class A
{
System.out.println("A inner");
}
}
public void newA() {
class A { // Local Class A
{
System.out.println("A local");
}
}
new A();
}
public static void main(String[] args) {
new Main().newA(); // prints "A local"
new Main().new A(); // prints "A inner"
//new A(); // compiler error: No enclosing instance of type Main is Accessible.
new B(); // but this works and prints "B outer"
}
}
Use the fully qualified class name:
new com.mypackage.A();
If your classes are in packages, I'd expect that to be the simplest way of achieving this. I don't believe there's any equivalent of the C# global:: for Java, to force this sort of thing.
Ultimately though, I'd just try to change the class names to avoid the problem happening in the first place. That's usually a better approach than using workarounds.
You should provide different package names for your two As so that they are clearly different types, then you can reference them by their full names.
For example:
my.package.for.toplevel.A outerA = new my.package.for.toplevel.A(); // prints "A outer"
// if this is the
// package
Or even better, use two different names for two distinct classes.
The name of the inner class is said to shadow the name of the top-level class. The top-level class cannot be referenced by its simple name in the scope of the inner class; the top-level class can only be referenced via a qualified name.
If the top-level class is in the default package (in which case its canonical name is the same as its simple name), you can still access it via reflection.
Yep, just use packages or avoid naming them the same from the beginning. I wonder what's your reason to name them the same anyway?
To explain your error, it comes from the fact that it tries to access the inner A, but since that class is not declared as static and there's no Main instance available, it can't create a non-static inner A that requires a reference to parent Main instance.
Assumed the classes are in the default package. To resolve naming conflict in this case needs either rename the conflicting classes or use the named package. Then use FQCN to resolve the issue.

How to create an alias for a private inner class (using XStream)?

I'm creating aliases for long class names... It works perfectly fine, but one of the serialized classes is a private inner class. I can't think of a way to create an alias for it other than making it public. I don't like this solution, because it should not be public in the first place. But since making an alias for it will make it possible to change package and class names without having to modify XML files (because the first tag is the fully qualified class name).
This is how I create aliases:
xstreamInstance.alias("ClassAlias", OuterClass.InnerClassToAlias.class);
That's why I need public access to that inner class.
So, if anyone knows a trick to alias a private inner class, I would really like to hear about it.
You could create a class like the following and pass your reference to the xstreamInstance to the alias method.
public class Parent {
public void alias(XStream x) {
x.alias("Kiddie", Parent.Child.class);
}
private class Child {
}
}
How about using annotations for the alias?
public class Parent {
#XStreamAlias("kiddie")
private class Child {
}
}
Edit: Alas, parsing of annotations of nested classes is not supported by XStream when asking to get the parent class parsed.

Categories

Resources