Getting HashMap values from fragments to activity through Interface - java

I would like to use interface to implement the communicate of passing data from fragments to activity's button which contains onClick event. I can see HashMap can write the data which is valid on editText field, but those value cannot be sent to activity. it shows error and stopped once I trigger the onClick event on activity.
I was confused on the usage of the interface. The errors as below appears after trying on debugging, waste around 3 days to handle on it and still cannot be resolve. Can anyone recommend or discuss how to solve it, thank you.
The errors:
Error:(77, 5) error: method does not override or implement a method from a supertype
Error:(39, 8) error: Fragment_step_2 is not abstract and does not override abstract method onPassValueStep2() in onPassValue2
Error:(231, 32) error: method onPassValueStep1 in class Fragment_step_1 cannot be applied to given types;
required: HashMap
found: no arguments
reason: actual and formal argument lists differ in length
Error:(232, 32) error: method onPassValueStep2 in class Fragment_step_2 cannot be applied to given types;
required: HashMap
found: no arguments
reason: actual and formal argument lists differ in length
Error:(78, 5) error: method does not override or implement a method from a supertype
Error:(36, 8) error: Fragment_step_1 is not abstract and does not override abstract method onPassValueStep1() in onPassValue
Main activity:
public interface onPassValue{
Map<Object, String> onPassValueStep1();
}
public interface onPassValue2{
Map<Object, String> onPassValueStep2();
}
protected void onCreate(Bundle savedInstanceState) {
......
btn_sendInsureInfo.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view){
//CALL here
//Fragment_step_1.onPassValueStep1();
//Fragment_step_2.onPassValueStep2();
......
}
}
......
Fragment_step_1: (xxx is activity's name)
public class Fragment_step_1 extends Fragment implements xxx.onPassValue {
......
HashMap insureApplicant = new HashMap<>(4);
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onAttach(Context xxx){
super.onAttach(xxx);
/*try {
passValue = (onPassValue) xxx;
} catch (ClassCastException e) {
throw new ClassCastException(pingan_insure_info.toString()
+ " didn't implement onPassValue");
}*/
}
#Override
public Map<Object, String> onPassValueStep1(HashMap insureResult) {
for (Object key : insureResult.entrySet()) {
//System.out.println(key + " fragment_1 : " + insureResult.get(key));
System.out.println(" fragment_1 : " + key);
Log.e("Hashmap", String.valueOf(insureResult));
}
return insureResult;
}
......
Fragment_step_2: (xxx is activity's name)
public class Fragment_step_2 extends Fragment implements xxx.onPassValue2{
......
RelativeLayout correspondence;
HashMap insureApplicant2 = new HashMap<>(3);
#Override
public void onAttach(Context pingan_insure_info){
super.onAttach(pingan_insure_info);
/*try {
passValueStep2 = (onPassValueStep2) xxx;
} catch (ClassCastException e) {
throw new ClassCastException(xxx.toString()
+ " didn't implement onPassValue");
}*/
}
#Override
public Map<Object, String> onPassValueStep2(HashMap insureApplicantStep2){
for (Object key : insureApplicantStep2.entrySet()) {
System.out.println("fragment_2 : " + key);
Log.e("Hashmap2", String.valueOf(insureApplicantStep2));
}
return insureApplicant2;
}
All fragments' editText will be filled after the editText is valid and typing by user and send to the function and stored in HashMap.
For example: (AddTextChangedListener with TextWatcher)
residentAddress.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
#Override
public void afterTextChanged(Editable editable) {
residentAddress.setOnFocusChangeListener(new View.OnFocusChangeListener(){
#Override
public void onFocusChange(View view, boolean isFocus){
if(!isFocus){
if("".trim().equals(residentAddress.getText().toString())){
rAddress.setError("Resident Address is required.");
strAddress = "";
insureApplicant2.put(2, strAddress);
} else {
rAddress.setErrorEnabled(false);
rAddress.setError(null);
strAddress = residentAddress.getText().toString().trim();
insureApplicant2.put(2, strAddress);
onPassValueStep2(insureApplicant2);
}
}
}
});
}
});

The signature in the Fragment of your interface's methods are wrong. You declared the interface like:
public interface onPassValue{
Map<Object, String> onPassValueStep1();
}
public interface onPassValue2{
Map<Object, String> onPassValueStep2();
}
and in the Fragment you have public
public Map<Object, String> onPassValueStep1(HashMap insureResult) {
Map<Object, String> onPassValueStep2(HashMap insureApplicantStep2){
as you can notice, the methods declared in your interfaces have no parameters.
You can either change your the method declaration in your interface, adding the missing parameter, or change the methods in the Fragment

Related

How could i get Class<? extends List<AlarmRule>> instatnce?

I need to get Class< ? extends List < AlarmRule > > instance.
This is my code:
public static BoundedMatcher<Object, List<AlarmRule>> setBind() {
Class<? extends List<AlarmRule>> clazz = null; // I need to give clazz a value,but i don't know how.
return new BoundedMatcher<Object, List<AlarmRule>>(clazz) {
#Override
public void describeTo(Description description) {
description.appendText("with item content: ");
}
#Override
protected boolean matchesSafely(List<AlarmRule> list) {
return list.stream().anyMatch(alarmRule -> test_reminder_corn.equals(alarmRule.cron));
}
};
}
Thanks for any help!
write like this
public static BoundedMatcher<Object, List> setBind() {
return new BoundedMatcher<Object, List>(List.class) {
#Override
public void describeTo(Description description) {
description.appendText("with item content: ");
}
#Override
protected boolean matchesSafely(List list) {
// convert every object in list to AlarmRule
return false;
}
};
}
In your case you need to pass List.class in the constructor.
However, because of java type erasure, any List may be passed to your matcher so you need to add additional code to ensure your list actually contains AlarmRule objects or you will get a ClassCastException at runtime.

implementing Parcelable in a derived-graphic class for onSaveInstanceState(Bundle)

I want to save and restore some data for screen orientation changes (portrait/landscape).
For doing it, I implemented onSaveInstanceState and onRestoreInstanceState in my class that holds the list that I want to restore. It seems to be working, and in MyObject class I implemented Parcelable.
The problem is that my object extends GifImageButton and implement Parcelable so I get this error in my object constructors: "There is no default constructor available for pl.droidsonroids.gif.GifImageButton"
public class MyDerivedClass extends MyBaseClass { // extends AppCompatActivity
ArrayList<MyObject> list;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.episode_five);
if(savedInstanceState == null || !savedInstanceState.containsKey("key")) {
String[] colors = {"black", "red"};
String[] numbers = {"one", "two"};
list = new ArrayList<MyObject>();
for(int i = 0; i < numbers.length; i++)
list.add(new MyObject(numbers[i], colors[i]));
}
else {
list = savedInstanceState.getParcelableArrayList("key");
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putParcelableArrayList("key", list);
super.onSaveInstanceState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle inState) {
list = inState.getParcelableArrayList("key");
super.onSaveInstanceState(inState);
init();
}
public void init() {
list.add(new MyObject("three", "transparent"));
list.add(new MyObject("for", "white"));
}
}
and for the problem, view the code below:
I want to extends GifImageButton but then I get an error "There is no default constructor available for pl.droidsonroids.gif.GifImageButton" at:
public MyObject(String number, String color)
AND public MyObject(Parcel in)
Note: if I remove: "extends GifImageButton" and "public MyObject(Context context, AttributeSet attrs)" then the code is compiled.
class MyObject extends GifImageButton implements Parcelable {
String color;
String number;
public MyObject(Context context, AttributeSet attrs) {
super(context, attrs);
setImageResource(R.drawable.a);
}
public MyObject(String number, String color) {
this.color = color;
this.number = number;
}
private MyObject(Parcel in) {
color = in.readString();
number = in.readString();
}
public int describeContents() {
return 0;
}
#Override
public String toString() {
return number + ": " + color;
}
public void writeToParcel(Parcel out, int flags) {
out.writeString(color);
out.writeString(number);
}
public static final Parcelable.Creator<MyObject> CREATOR = new Parcelable.Creator<MyObject>() {
public MyObject createFromParcel(Parcel in) {
return new MyObject(in);
}
public MyObject[] newArray(int size) {
return new MyObject[size];
}
};
}
Can I extend GifImageButton in my object class that implements Parcelable? if not then how can I fix it?
The error message appears because you need to call a constructor of the superclass in your constructor. If there is no explicit call, the compiler inserts a call to a constructor without arguments. However, all the super class constructors have some arguments, that's why the compilation fails.
In your case I wouldn't implement Parcelable in your class at all. The superclass doesn't implement it, so you'd need to somehow save the state of the superclass also, which will not be possible to do. The superclass is a View, so it retains a reference to the current activity, which can't be put into a Parcel.
What you should do instead is save not the instance itself, but the state you need. Your state is currently expressed by two strings. You can create a separate class State inside MyObject:
static class State implements Parcelable {
private String color;
private String number;
//Parcelable implementation omitted
}
Then you implement Parcelable for it. MyObject will have a field private State state instead of the current two fields, a constructor which takes a State, and a method State getState(), which will return the state. When you need to save the state, you don't save the object, you get its state and save it instead. When you need to restore, you restore the State first, then use it with the constructor to create a new MyObject with the same state as before.
you MyObject class has private constructor MyObject(Parcel in), make it public so compiler can access it

Derive async task in android

I have a set of APIs which are implemented using AsyncTask. Some of them have different signature( Some have progress reporting, some others have different datatype being sent as Params). But, all of these APIs return a boolean Result. On success, app Logic for successful calling of API is done. On failure, a generic error popup with error message is shown. Now I want to derive a class from AsyncTask in such a way that it implements a function onSuccessResult as well as overrides a function onFailureResult.
//I get error Params, Progress not recognized.
public class ServerAPIAsyncTask extends AsyncTask<Params, Progress, Boolean>{
abstract public void onSuccessResult();
public void onFailureResult() {
int err = getErrorCode();
showPopup(err);
}
#override
protected void onPostExecute(final Boolean success) {
if (success)
onSuccessResult();
else
onFailureResult();
}
}
Please note that I have to do all of this with two generic datatypes Params and Progress. How can I achieve this? I want to achieve this for two reasons. First I want to derive from this new class like this:
public class getCarDetailAPITask extends ServerAPIAsyncTask<Garage, void, Boolean> {
#Override
protected Boolean doInBackground(Void... params) {
//call my api
}
#Override
protected void onPostExecute(final Boolean success) {
super.onPostExecute(success);
}
#Override
public void onFailureResult() {
super.onFailureResult();
}
#Override
public void onSuccessResult() {
//Do app logic
}
}
Secondly, it helps me to keep the onFailureResult logic at one place thus, not repeating it over and again.
For Params, Progress and Result you need to pass in actual classes when you extend AsyncTask. Since you don't have classes in your class-path that match the names Params and Progress you get these errors.
public class ServerAPIAsyncTask extends AsyncTask<Void, Void, Boolean>{
abstract public void onSuccessResult();
public void onFailureResult() {
int err = getErrorCode();
showPopup(err);
}
protected void onPostExecute(final Boolean success) {
if (success)
onSuccessResult();
else
onFailureResult();
}
}
For your second AsyncTask you should extend AsyncTask, not your own derived ServerAPIAsyncTask. Also, the first Parameter Garage needs to match the parameter you pass into doInBackground, see below:
public class GetCarDetailAPITask extends AsyncTask<Garage, Void, Boolean> {
#Override
protected Boolean doInBackground(Garage... params) {
//call my api
}
protected void onPostExecute(final Boolean success) {
super.onPostExecute(success);
}
#Override
public void onFailureResult() {
super.onFailureResult();
}
#Override
public void onSuccessResult() {
//Do app logic
}
}
According to your comment, there you have generic AsyncTask example:
public class MyAsyncTask<A,B> extends AsyncTask<A, Void, B> {
#Override
protected B doInBackground(A... params) {
return null;
}
// Other methods
}
You said this
//I get error Params, Progress not recognized.
public class ServerAPIAsyncTask extends AsyncTask<Params, Progress, Boolean>
Params and Progress are not real classes. They need to be real classes present in your package.
Some of them have different signature( Some have progress reporting, some others have different datatype being sent as Params).
Different datatype being sent as param? So set params to Object type. It is the superclass of all classes.
See this example, taken from AsyncTask documentation itself:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}

How to handle generics inside a Java "annotation processor"?

I asked before for an example "annotation processor" that would generate a Proxy/Delegate for an interface, but got no answer, and did not find anything on the Internet, so I made my own.
So far it worked well, until I tried to use generics inside a super-interface. If I use generics in the annotated interface, it works fine (more by accident than by design). But if the annotated interface extends another interface that takes a generic type parameter, that parameter is not "bound" to the type that the annotated interface use when extending the super-interface. Example:
public interface TestFragment<E> {
void test(E dummy);
}
#CreateWrapper
public interface TestService extends TestFragment<String> {
double myOwnMethod();
}
This would generate:
// ...
public void test(final E dummy) {
wrapped.test(dummy);
}
// ...
instead of the correct:
// ...
public void test(final String dummy) {
wrapped.test(dummy);
}
// ...
The code that generates the parameters in the generated methods look like this:
int count = 0;
for (VariableElement param : method.getParameters()) {
if (count > 0) {
pw.print(", ");
}
count++;
pw.printf("final %s %s", param.asType().toString(),
param.getSimpleName().toString());
}
Is there a way to do this?
Have a look at http://docs.oracle.com/javase/6/docs/api/javax/lang/model/util/Types.html#asMemberOf%28javax.lang.model.type.DeclaredType,%20javax.lang.model.element.Element%29
Might be helpful. I used it to solve a very similar problem.
This can be quite simple if you follow Ryan Walls suggestion of using asMemberOf
ExecutableType methodType = (ExecutableType) typeUtil
.asMemberOf((DeclaredType) theAnnotatedClass.asType(), method);
int count = 0;
for (VariableElement param : method.getParameters()) {
if (count > 0) {
pw.print(", ");
}
TypeMirror actualParamType = methodType.getParameterTypes().get(count);
pw.printf("final %s %s", actualParamType.toString(),
param.getSimpleName().toString());
count++;
}
What you need is substitution, given a map of type variables to type arguments. In this case, E->String. Replace any E in any type with String
There is no such support in javax.lang.model.util.Types, you need to roll your own. Basically
void print(TypeMirror type, Map<TypeVariable,TypeMirror> substitution)
if(substitution.containsKey(type)) // type is a var, E
print( substitution.get(type) ); // String
else if(type instanceof DeclaredType) // e.g. List<E>
print( type.asElement().getSimpleName() ); // List
for(TypeMirror arg : type.getTypeArguments() ) // E
print(arg, substitution)
etc. something like that
Copy-paste of my original answer:
This seems to be a common question so, for those arriving from Google: there is hope.
The Dagger DI project is licensed under the Apache 2.0 License and contains some utility methods for working with types in an annotation processor.
In particular, the Util class can be viewed in full on GitHub (Util.java) and defines a method public static String typeToString(TypeMirror type). It uses a TypeVisitor and some recursive calls to build up a string representation of a type. Here is a snippet for reference:
public static void typeToString(final TypeMirror type, final StringBuilder result, final char innerClassSeparator)
{
type.accept(new SimpleTypeVisitor6<Void, Void>()
{
#Override
public Void visitDeclared(DeclaredType declaredType, Void v)
{
TypeElement typeElement = (TypeElement) declaredType.asElement();
rawTypeToString(result, typeElement, innerClassSeparator);
List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
if (!typeArguments.isEmpty())
{
result.append("<");
for (int i = 0; i < typeArguments.size(); i++)
{
if (i != 0)
{
result.append(", ");
}
// NOTE: Recursively resolve the types
typeToString(typeArguments.get(i), result, innerClassSeparator);
}
result.append(">");
}
return null;
}
#Override
public Void visitPrimitive(PrimitiveType primitiveType, Void v) { ... }
#Override
public Void visitArray(ArrayType arrayType, Void v) { ... }
#Override
public Void visitTypeVariable(TypeVariable typeVariable, Void v)
{
result.append(typeVariable.asElement().getSimpleName());
return null;
}
#Override
public Void visitError(ErrorType errorType, Void v) { ... }
#Override
protected Void defaultAction(TypeMirror typeMirror, Void v) { ... }
}, null);
}
I am busy with my own project which generates class extensions. The Dagger method works for complex situations, including generic inner classes. I have the following results:
My test class with field to extend:
public class AnnotationTest
{
...
public static class A
{
#MyAnnotation
private Set<B<Integer>> _bs;
}
public static class B<T>
{
private T _value;
}
}
Calling the Dagger method on the Element the processor provides for the _bs field:
accessor.type = DaggerUtils.typeToString(element.asType());
The generated source (custom, of course). Note the awesome nested generic types.
public java.util.Set<AnnotationTest.B<java.lang.Integer>> AnnotationTest.A.getBsGenerated()
{
return this._bs;
}
EDIT: adapting the concept to extract a TypeMirror of the first generic argument, null otherwise:
public static TypeMirror getGenericType(final TypeMirror type)
{
final TypeMirror[] result = { null };
type.accept(new SimpleTypeVisitor6<Void, Void>()
{
#Override
public Void visitDeclared(DeclaredType declaredType, Void v)
{
List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
if (!typeArguments.isEmpty())
{
result[0] = typeArguments.get(0);
}
return null;
}
#Override
public Void visitPrimitive(PrimitiveType primitiveType, Void v)
{
return null;
}
#Override
public Void visitArray(ArrayType arrayType, Void v)
{
return null;
}
#Override
public Void visitTypeVariable(TypeVariable typeVariable, Void v)
{
return null;
}
#Override
public Void visitError(ErrorType errorType, Void v)
{
return null;
}
#Override
protected Void defaultAction(TypeMirror typeMirror, Void v)
{
throw new UnsupportedOperationException();
}
}, null);
return result[0];
}

Find type parameter of method return type in Java 6 annotation processor

I'm writing a tool that uses the annotation processor to generate source code depending on the return type of methods of an annotated class. The return type is always some subtype (interface or class) of an interface A that defines a type variable T.
interface A<T>{T m();};
I would like to find the type parameter for the method m() return value type variable T.
The return type is represented by the annotation processor as a javax.lang.model.type.TypeMirror instance. The simplest case is to return A<T> directly.
#SomeAnnotation
class SomeClass{
A<T> x();
}
The processor code to find out T is quite simple. (I'll cast instead of using the visitor API here to keep the code simple.)
DeclaredType type = (DeclaredType) typeMirror;
TypeMirror t = type.getTypeArguments().get(0);
The TypeMirror of the return type is a javax.lang.model.type.DeclaredType and T is the first type argument. The result t is a javax.lang.model.type.TypeVariable for T. The same works for a concrete return type A<B> (B is some type: interface B{}). The result for t is a DeclaredType representing B.
Things start to get complicated with other result types:
interface Subtype<T> extends A<T>{}
interface Concrete extends A<B>{};
interface Multiple<B,T> extends A<T>{}
interface Bounds<T extends B> extends A<T>{}
interface Hierarchy extends Concrete{}
Subtype<B> -> DeclaredType B
Subtype<T> -> TypeVariable T
Concrete -> DeclaredType B
Multiple<B,T> -> TypeVariable T or DeclaredType B depeding on Multiple
Multiple<B,B> -> TypeVariable B
<T extends B> A<T> -> TypeVariable T with super class bound B
Bound<B> -> DeclaredType B
Bound<C> -> DeclaredType C (subtype of B)
Hierarchy -> TypeVariable T
Is there a way to find the correct type parameter for T without mirroring the whole java type system?
Have a look at http://docs.oracle.com/javase/6/docs/api/javax/lang/model/util/Types.html#asMemberOf%28javax.lang.model.type.DeclaredType,%20javax.lang.model.element.Element%29
I used it to solve this problem and contributed the solution to the WsDoc project in this pull request: https://github.com/versly/wsdoc/pull/7
I did something like this:
Type.MethodType methodType = (Type.MethodType) processingEnv.getTypeUtils().asMemberOf(declaredTypeThatExtendsSomeGenericParent, methodToGetReturnTypeForAsExecutableElement);
TypeMirror type = methodType.getReturnType();
public AnnotationProcessor getProcessorFor(
Set<AnnotationTypeDeclaration> atds,
AnnotationProcessorEnvironment env) {
return new SomeAnnotationProcessor(env);
}
private static class SomeAnnotationProcessor implements AnnotationProcessor {
private final AnnotationProcessorEnvironment env;
SomeAnnotationProcessor(AnnotationProcessorEnvironment env) {
this.env = env;
}
public void process() {
for (TypeDeclaration typeDecl : env.getSpecifiedTypeDeclarations()) {
System.out.println("in class: " + typeDecl);
typeDecl.accept(getDeclarationScanner(
new SomeClassVisitor(), NO_OP));
}
}
private static class SomeClassVisitor extends SimpleDeclarationVisitor {
#Override
public void visitMethodDeclaration(
MethodDeclaration methodDeclaration) {
System.out.println("visiting method: "+methodDeclaration + " -> "+methodDeclaration.getReturnType());
methodDeclaration.getReturnType().accept(new SomeTypeVisitor());
}
}
}
private static class SomeTypeVisitor implements TypeVisitor {
public void visitClassType(ClassType classType) {
System.out.println("classType: " + classType + " -> "+classType.getClass());
}
#Override
public void visitInterfaceType(InterfaceType interfaceType) {
Types types = annotationProcessorEnvironment.getTypeUtils();
TypeDeclaration typeDeclaration = annotationProcessorEnvironment
.getTypeDeclaration("A");
Collection<InterfaceType> superinterfaces = interfaceType
.getSuperinterfaces();
System.out.println("interfaceType: " + interfaceType + " -> "
+ superinterfaces);
DeclaredType typeOfA = types.getDeclaredType(typeDeclaration);
boolean isSubTypeOfA = types.isSubtype(interfaceType, typeOfA);
if (isSubTypeOfA) {
findTypeVariable(types, superinterfaces, typeOfA);
}
Iterator<TypeMirror> iterator = interfaceType
.getActualTypeArguments().iterator();
while (iterator.hasNext()) {
TypeMirror next = iterator.next();
next.accept(new SomeTypeVisitor());
}
}
public void visitTypeVariable(TypeVariable typeVariable) {
System.out.println("typeVariable: "
+ typeVariable.getDeclaration() + " -> "+typeVariable.getClass());
}
private void findTypeVariable(Types types,
Collection<InterfaceType> superinterfaces, DeclaredType typeOfA) {
for (InterfaceType superInterface : superinterfaces) {
TypeMirror erasure = types.getErasure(superInterface);
if (erasure.equals(typeOfA)) {
System.out.println("true, "+superInterface.getActualTypeArguments());
} else {
System.out.println("false: " + typeOfA + " =!= "
+ erasure);
findTypeVariable(types, superInterface.getSuperinterfaces(), typeOfA);
}
}
}
}
This seems to be a common question so, for those arriving from Google: there is hope.
The Dagger DI project is licensed under the Apache 2.0 License and contains some utility methods for working with types in an annotation processor.
In particular, the Util class can be viewed in full on GitHub (Util.java) and defines a method public static String typeToString(TypeMirror type). It uses a TypeVisitor and some recursive calls to build up a string representation of a type. Here is a snippet for reference:
public static void typeToString(final TypeMirror type, final StringBuilder result, final char innerClassSeparator)
{
type.accept(new SimpleTypeVisitor6<Void, Void>()
{
#Override
public Void visitDeclared(DeclaredType declaredType, Void v)
{
TypeElement typeElement = (TypeElement) declaredType.asElement();
rawTypeToString(result, typeElement, innerClassSeparator);
List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
if (!typeArguments.isEmpty())
{
result.append("<");
for (int i = 0; i < typeArguments.size(); i++)
{
if (i != 0)
{
result.append(", ");
}
// NOTE: Recursively resolve the types
typeToString(typeArguments.get(i), result, innerClassSeparator);
}
result.append(">");
}
return null;
}
#Override
public Void visitPrimitive(PrimitiveType primitiveType, Void v) { ... }
#Override
public Void visitArray(ArrayType arrayType, Void v) { ... }
#Override
public Void visitTypeVariable(TypeVariable typeVariable, Void v)
{
result.append(typeVariable.asElement().getSimpleName());
return null;
}
#Override
public Void visitError(ErrorType errorType, Void v) { ... }
#Override
protected Void defaultAction(TypeMirror typeMirror, Void v) { ... }
}, null);
}
I am busy with my own project which generates class extensions. The Dagger method works for complex situations, including generic inner classes. I have the following results:
My test class with field to extend:
public class AnnotationTest
{
...
public static class A
{
#MyAnnotation
private Set<B<Integer>> _bs;
}
public static class B<T>
{
private T _value;
}
}
Calling the Dagger method on the Element the processor provides for the _bs field:
accessor.type = DaggerUtils.typeToString(element.asType());
The generated source (custom, of course). Note the awesome nested generic types.
public java.util.Set<AnnotationTest.B<java.lang.Integer>> AnnotationTest.A.getBsGenerated()
{
return this._bs;
}
EDIT: adapting the concept to extract a TypeMirror of the first generic argument, null otherwise:
public static TypeMirror getGenericType(final TypeMirror type)
{
final TypeMirror[] result = { null };
type.accept(new SimpleTypeVisitor6<Void, Void>()
{
#Override
public Void visitDeclared(DeclaredType declaredType, Void v)
{
List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
if (!typeArguments.isEmpty())
{
result[0] = typeArguments.get(0);
}
return null;
}
#Override
public Void visitPrimitive(PrimitiveType primitiveType, Void v)
{
return null;
}
#Override
public Void visitArray(ArrayType arrayType, Void v)
{
return null;
}
#Override
public Void visitTypeVariable(TypeVariable typeVariable, Void v)
{
return null;
}
#Override
public Void visitError(ErrorType errorType, Void v)
{
return null;
}
#Override
protected Void defaultAction(TypeMirror typeMirror, Void v)
{
throw new UnsupportedOperationException();
}
}, null);
return result[0];
}

Categories

Resources