Create a new PSIClass with Generic type parameters - intellij-plugin

Newbie question on IntelliJ plugin development.
I need to generate a parameterised class (Class with generics) given the name of the class and the name of the type parameter, but I can not find how to?
It seems PSIClass does not support generics.
Example
Given
String className = "MyClass";
String typeName = "T"
I would like to have a PSIClass that represents this:
public class MyClass<T> { ... }
The goal is to dynamically add methods to such class and eventually write the complete class to a file. The class needs to declare the Type Variable because some methods will receive/return T
Thanks!

I have found a solution in the intelliJ developer forums. It doesn't seem to be the neatest one, but it works.
I'd recommend to use
PsiFileFactory.getInstance(...).createFileFromText("ClassName.java",
JavaFileType.INSTANCE, "class ClassName { ...}"), cast the result
to PsiJavaFile and use its getClasses[0] as the result.
Here is the link to the thread:
https://intellij-support.jetbrains.com/hc/en-us/community/posts/115000089970-Create-a-new-PSIClass-with-Generic-type-parameters?page=1#community_comment_115000122164

Related

Kotlin's reflection: Simple variable extraction out of String

I've read about reflection in both Kotlin and Java documentation & getattr in Python examples but they all seem to lack my use case:
I have variables of type multableLiveData<boolean> like repetitionOfElementsInNewExerciseAllowed in a ViewModel class (Android programming) that I need to update from a different class like HomeFragment.
My unsexy approach was the following function in ViewModel:
fun updateBoolElement (boolElementToUpdate:String, valueToUpdateWith:Boolean){
when (boolElementToUpdate){
"repetitionOfElementsInNewExerciseAllowed" -> repetitionOfElementsInNewExerciseAllowed.value=valueToUpdateWith
}
}
Instead of this I'm striving for a recursive approach to extract the variable's name whose value I want to change out of the string boolElementToUpdate like this (pseudo code):
fun updateBoolElement (boolElementToUpdate:String, valueToUpdateWith:Boolean){
getAttributeReferenceByName(boolElementToUpdate).value = valueToUpdateWith
}
The way I would like to reuse the function is by calling it with different varible names then like
sharedViewModel.updateBoolElement("repetitionOfElementsInNewExerciseAllowed",repetitionOfElementsInNewExerciseAllowed)
or more abstractly
sharedViewModel.updateBoolElement("newVariableName",newBoolValue)
Is reflection or any other structure in Kotlin capable of doing such wizardry? Thanks for any hint!

KotlinPoet how to get TypeName of generated class

I want to use a class generated with TypeSpec.classBuilder as a property in another class that I am generating. But for this I need to get a TypeName and I cannot find a way to access it. Only from the superclass. Anyone knows a way to do this?
You should be perfectly fine with using ClassName there.
And the easiest way of obtaining the ClassName is to pass the package and the name of the generated type:
ClassName("your.package.here", "NameOfType")
You can see here how I'm specifying a receiver of an extension function ("similar" use-case):

Kotlin equivalent of class properties, constructors, empty parameter constructors, getters and setters

I am currently practicing in developing kotlin and as of now I seem to get confused with kotlin's class structure.
this is a code in java
//properties
private String var;
//constructor
public SampleClass(String var){
this.var = var;
}
public SampleClass(){
}
//getters and setters
public String getVar(){
return this.var;
}
public String setVar(String var){
this.var = var;
}
what's the kotlin equivalent of this ?
This is the equivalent Kotlin code for your Java code:
class SampleClass(var `var`: String? = null)
There are a few things to note:
Your Java snippet above omits the wrapping class SampleClass code
Your setVar() indicates that it returns a String, but it's actually void. I assume you intended for it to have a void return type.
Your property var is not ideal for Kotlin, because it's a reserved word. That's why we have to escape it with backticks. (It could also be kind of confusing in Java 10, since var is a reserved type name there now).
Here's why this one-liner is equivalent to the Java listing.
The constructor part - the part between the parentheses - can be used to accept constructor arguments, but by putting the Kotlin keyword var at the beginning, we tell Kotlin that we want this to also be a property. Kotlin will create a getter and setter for it.
The String? part makes this property of type nullable String.
Instead of creating two different constructors, we just give our var property argument a default value of null by using = null. When creating this class from Java, it'll still show up as two constructors.
If you're using IntelliJ or Android Studio, you can tell it to convert any Java class to Kotlin. Just open the class file, and go to the Code menu, and choose Convert Java file to Kotlin file. It won't necessarily generate very idiomatic code (e.g., it might create two constructors instead of using a default for the constructor argument), but it'll get you started.
For "what is Kotlin equivalent of some code in Java", there is an universal answer: copy the Java code and paste it into a Kotlin file in IDEA/Android Studio. Or convert the entire file.
On the web, you can use https://try.kotlinlang.org/#/Kotlin%20Koans/Introduction/Java%20to%20Kotlin%20conversion/Task.kt.

How to put class dynamically in <>

I know there are various capabilities in Java with reflection.
For example:
Class<?> clazz = Class.forName("java.util.Date");
Object ins = clazz.newInstance();
I wonder if I could pass class dynamicaly in some method declaration in <> tags (or there is other way to do it if it must be fixed). I would like to change that class declaration dynamicaly; because I would like to write generic method for all types of classes.
In there, I have this:
List<Country>
Can I write it something diffrent with reflection? For example can it be somehow be achieved to pass class as parameter (or how else should be this done):
List<ins>
? I would appreciate examples.
This cannot be done because generics are a compile time feature. Once code is compiled, the only place where generics are exists are at method signatures, and they are only used for compiling new code.
When working with reflection, you are basicly working with raw types, and need to code according to that, that means, you can cast the returned result of newInstance() to the list type your need, for example:
List<Country> ins = (List<Country>)clazz.newInstance();
This is a safe operation to do, because you know at that point its empty, and isn't passed to any outside code.
I don't think this is possible. Generics in Java are implemented in a way that prohibits runtime access.
Generics are there so that the compiler can verify correct typing, but are no longer present at runtime (this is called "type erasure"). Reflection deals with the runtime representation of types only. As far as I know the only case where reflection has to deal with generics is to find out "fixed" type parameters of sub-classes, e.g. when you have class Bar<T> and class Foo extends Bar<String>, you can find out that the T of Bar is fixed to String in Foo using reflection. However, this is information found in the class file, too. Except that, reflection can only see or create raw-types.

Jackson constructParametricType is deprecated, but constructParameterizedType doesn't work the same

Here is my code snippet, and the newer "constructParameterizedType" doesn't match my needs (unless I am missing something, which I assume I am). I have a genericized class called Result where T is any basic class that extends my "Inflatable" base class. represents the data records coming back from Salesforce REST API... so here is example of code that is working:
Class c = Class.forName("sfshare.UserRecord" );
JavaType type = mapper.getTypeFactory().constructParametricType(Result.class, c);
Result<T> res = mapper.readValue(rspData, type);
But if I use the newer (non-deprecated) "constructParameterizedType()" method, this same code will not compile because it isn't matching the parameters of constructParameterizedType. But constructParameterizedType isn't in use much yet and there are no examples to use... only the Javadoc - which doesn't make sense for my use-case.
If you look at arguments and specifically Javadocs, you will note that there is a new type: 2nd argument is the intended 'target' for parameters.
To give an example of meaning is that if you want to construct equivalent of:
ArrayList<String>
what you want to pass as arguments are:
constructParameterizedType(ArrayList.class, List.class, String.class)
or, possibly, Collection.class for second argument.
Think of it as the underlying relevant type you are trying to provide parameters for.
The underlying reason for this change is somewhat complicated and has to do with handling of "add-on" interfaces like Iterable<T>: for those cases it is necessary to provide different classes.
But in most end-user use cases you will just need to pass the same class as first and second argument.
Try this:
Class c = Class.forName("sfshare.UserRecord");
TypeFactory typeFactory = mapper.getTypeFactory();
JavaType type = typeFactory.constructParametrizedType(Result.class, Result.class, c);
Result<T> res = mapper.readValue(rspData, type);
or if your Result<T> class implements an interface:
JavaType type = typeFactory.constructParametrizedType(Result.class, ResultInterface.class, c);