Android annotation at runtime - android

I want to annotate a list of classes with a custom annotation, which I need at runtime.
My annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface CustomAnnotation {
String value() default "defaultValue";
}
My custom class is:
#CustomAnnotation
public class MyClass {
}
Now, I want to read the annotation from a class name, which I has as string. Code is without error handling (for easy handling):
String className = "com.example.MyClass";
Class clazz = Class.forName(className);
Annotation[] annotation = clazz.getAnnotation(); // is empty
Why is clazz.getAnnotation() empty? Has someone an idea?

Just tested your code - it works for me.
Only need to call getAnnotations()
The issue is definitely out of code you posted.

Related

How to replace method reference(::) in java to normal constructor call?

Earlier I have model class in java which uses autovalue. Now, it's converted to Kotlin data class.
Model Class -->
public static SampleClass create(
#NonNull final SamplePost post,
#NonNull final List<SampleComment> comments) {
return new AutoValue_SampleClass(post, comments);
}
Calling Class -->
return Observable.zip(...
SampleClass::create);
}
new data class -->
data class SampleClass(val post: DiscussionPost,
val comments: List<SampleComment>) : Parcelable
Now how to call it for data class?
U can use SampleClass::new to call the constructor.
If I understand correctly, you don't need a constructor call, but a constructor reference. The syntax for it is ::SampleClass. But this may not trigger SAM conversion, in which case you'll need
Observable.zip(...,
{ post, comments -> SampleClass(post, comments) })
EDIT: The above assumes that zip is called from Kotlin, if you want to call it from Java, see #ebasha's answer.

Android Firebase - How to push Child object which extend Abstract class [duplicate]

I'm using the new firebase sdk for android and use the real database feature. When i use the getValue(simple.class) everything is fine. But when i want to parse a class which is a subclass, all the attribute of the mother class are null, and i have this type of error:
No setter/field for name found on class uk.edume.edumeapp.TestChild
public class TestChild extends TestMother {
private String childAttribute;
public String getChildAttribute() {
return childAttribute;
}
}
public class TestMother {
protected String motherAttribute;
protected String getMotherAttribute() {
return motherAttribute;
}
}
this function
snapshot.getValue(TestChild.class);
motherAttribute attribute is null, and I get
No setter/field for motherAttribute found on class uk.edume.edumeapp.TestChild
the Json that i parse is:
{
"childAttribute" : "attribute in child class",
"motherAttribute" : "attribute in mother class"
}
Firebaser here
This is a known bug in some versions of the Firebase Database SDK for Android: our serializer/deserializer only considers properties/fields on the declared class.
Serialization of inherited properties from the base class, is missing in the in releases 9.0 to 9.6 (iirc) of the Firebase Database SDK for Android. It was added back in versions since then.
Workaround
In the meantime you can use Jackson (which the Firebase 2.x SDKs used under the hood) to make the inheritance model work.
Update: here's a snippet of how you can read from JSON into your TestChild:
public class TestParent {
protected String parentAttribute;
public String getParentAttribute() {
return parentAttribute;
}
}
public class TestChild extends TestParent {
private String childAttribute;
public String getChildAttribute() {
return childAttribute;
}
}
You'll note that I made getParentAttribute() public, because only public fields/getters are considered. With that change, this JSON:
{
"childAttribute" : "child",
"parentAttribute" : "parent"
}
Becomes readable with:
ObjectMapper mapper = new ObjectMapper();
GenericTypeIndicator<Map<String,Object>> indicator = new GenericTypeIndicator<Map<String, Object>>() {};
TestChild value = mapper.convertValue(dataSnapshot.getValue(indicator), TestChild.class);
The GenericTypeIndicator is a bit weird, but luckily it's a magic incantation that can be copy/pasted.
This was apparently finally fixed in release 9.6.
Fixed an issue where passing a derived class to DatabaseReference#setValue() did not correctly save the properties from the superclass.
for:
No setter/field for motherAttribute found on class uk.edume.edumeapp.TestChild
put setter for TestChild class:
public class TestMother {
private String motherAttribute;
public String getMotherAttribute() {
return motherAttribute;
}
//set
public void setMotherAttribute(String motherAttribute) {
this.motherAttribute= motherAttribute;
}
}
Check this https://firebase.google.com/support/guides/firebase-android
it says
"If there is an extra property in your JSON that is not in your Java class, you will see this warning in the log files: W/ClassMapper: No setter/field for ignoreThisProperty found on class com.firebase.migrationguide.ChatMessage
"
Blockquote
You can get rid of this warning by putting an #IgnoreExtraProperties annotation on your class. If you want Firebase Database to behave as it did in the 2.x SDK and throw an exception if there are unknown properties, you can put a #ThrowOnExtraProperties annotation on your class.
Blockquote

Usage of parceler (#Parcel) with Realm.io (Android)

I have the following code which produces the error: Error:Parceler: Unable to find read/write generator for type io.realm.Realm for io.realm.RealmObject.realm
It was working all fine without extends RealmObject , however I want to use Realm to put to database easily. Is there a way to exlcude the RealmObject fields and just use the basic pojo fields for #Parcel?
#Parcel
public class Feed extends RealmObject{
int id;
public String text;
public String time_created;
String time_modified;
int comments_count;
int likes_count;
String feed_type;
int obj_id;
String image;
String user_name;
String user_earthmile_points;
boolean liked;
boolean commented;
boolean is_private;
String url;
int feed_creator_id;
}
EDIT #2: Actually, I found a way to make it work :). See the updated answer below.
EDIT #1: While the app compiles just fine, it crashes when trying to actually create a Parcel with the error: org.parceler.ParcelerRuntimeException: Unable to create ParcelableFactory for io.realm.FeedRealmProxy. The Realm team has officially acknowledged that it is currently not possible to implement Parcelable on RealmObjects. It is unclear if / when this will be resolved.
With Parceler v0.2.16, you can do this:
#RealmClass // required if using JDK 1.6 (unrelated to Parceler issue)
#Parcel(value = Parcel.Serialization.BEAN, analyze = { Feed.class })
public class Feed extends RealmObject {
// ...
}
Then, use Parcels.wrap(Feed.class, feed) instead of Parcels.wrap(feed) everywhere, otherwise your app will crash with org.parceler.ParcelerRuntimeException: Unable to create ParcelableFactory for io.realm.FeedRealmProxy.
All classes that extend RealmObject will have a matching RealmProxy class created by the annotation processor. Parceler must be made aware of this class. Note that the class is not available until the project has been compiled at least once.
#Parcel(implementations = { PersonRealmProxy.class },
value = Parcel.Serialization.BEAN,
analyze = { Person.class })
public class Person extends RealmObject {
// ...}

Haxe: How can I setup a class to store data in an array of type that I pass in the constructor

I am coding in Haxe, Lime, OpenFl. I am trying to set up a Class to store data in a Map, referenced by class instance. The class type is to be passed in the constructor, via inference. But I am quite new to all this and can't quite figure out the syntax, this is what I got so far:
class DynamicStore<A>
{
private var hashA:Map<Class<A>,String>;
public function new<A>(paramA:Class<A>) {
hashA = new Map();
}
}
But this gives me the following error:
Abstract Map has no #:to function that accepts IMap<Class<DynamicStore.A>, String>
Is there a way to do this?
A question first:
do you really want to use classes as key? or objects?
In classes should be the key
It would be much simpler to use the classe's full name as key, like "mypackage.blob.MyClass". It's safer, easier to handle and debug.
Map<String, String>
Would suffice in that case.
If objects should be keys
Then the code would look like:
import haxe.ds.ObjectMap;
class Test<A>
{
static function main() {}
private var hashA :ObjectMap<A,String>;
public function new(paramA:A) {
hashA = new ObjectMap<A,String>();
}
}
The reason "Map" cannot be directly used in this case is that "Map" is a syntactic sugar, being resolved to StringMap, IntMap or others depending on the key type. If it doesn't know what kind of map to be used, it cannot proceed (this is mainly due to cross-compiling issues).
Remark
As a final note, I would mention your construction seems a bit wacky/strange to me. It would be interesting to know what you are trying to achieve and why you structure it the way you do.
I don't think you can use Class as the key of a Map. A good work around it to use a String as a key and the fully qualified names of the types. You can also define an abstract to move from the Type to String easily ... something like the following (code not-tested);
private var hashA : Map<String, String>;
public function addClass(className : ClassId, ...)
And the abstract will look something like this:
abstract ClassId(String) {
inline public function new(name : String) this = name;
#:from public static inline function fromClass(cls : Class<Dynamic>)
return new ClassId(Type.getClassName(cls));
#:to public inline function toClass() : Class<Dynamic>
return Type.resolveClass(this);
#:to public inline function toString() : String
return this;
}

How can I inject parameter through constructor in Roboguice? [android]

This question is probably exact duplicate of this one
Pass parameter to constructor with Guice
Difference is that I use roboguice for android, not just Guice, so answers there does not work for me.
Question is - how can I pass initialize parameters into created object? I.e. I have injected interface which should be initialize with some parameter which roboguice does not know.
What I see in link I provide, I should create factory interface and register it like this
void configure(Binder binder) {
binder.install(new FactoryModuleBuilder()
.implement(FooInterface.class, Foo.class)
.build(FooFactory.class));
}
But I can't find FactoryModuleBuilder class. I use Intellij IDEA, it can show me every class which I can access at current place and I can be 100% sure that there is no classes which starts with 'Factory' word.
How can I create my factory using roboguice?
UPDATED
I forgot to download guice-assistedinject. But still I can't figure out where should I register this factory.
UPDATE 2
Why I need that? Because there should be situation where some abstraction has dependency which could not be resolved by Roboguice. This dependency could be any type, even simple string or number.
In my case I have NumberPicker control on UI and I want to move all UI specific tasks in MyNumberPickerWrapper class. And when I create this wrapper I inject its dependency (this control) through constructor.
It's not the point if I am right with such approach, but that there could be a plenty of another more applicable example where constructor injection needed and this injected classes could not be created by Roboguice
I followed the steps of the answer given in Pass parameter to constructor with Guice and did slight modifications to run it under roboguice. Works completely fine for me.
add guice-assistinject library to gradle script
dependencies { compile 'com.google.inject.extensions:guice-assistedinject:4.+' }
Create Factory interface that with create method that accepts parameters the object constructor requires and returns object's interface
public interface ICustomObjectFactory {
ICustomObject create(String queueName);
}
Add #Inject annotation to constructor of the object and #Assisted annotation to each parameter coming from factory.
public class CustomObject implements ICustomObject {
protected String name;
#Inject
public CustomObject(#Assisted String name){
this.name = name;
}
}
Add binding into the Module that you are using
public class SomeModule extends AbstractModule {
#Override
protected void configure() {
install(new FactoryModuleBuilder()
.implement(ICustomObject.class, CustomObject.class)
.build(ICustomObjectFactory.class));
}
}
Inject factory and create instances of your object
public class SomeClass {
#Inject ICustomObjectFactory factory;
public SomeClass () {
ICustomObject first = this.factory.create("first");
ICustomObject second = this.factory.create("second");
}
}
I faced this same problem and I succeed thanks to Pavel's answer. I only have had to struggle with some errors, and I don't know if it's due to the versions of the libraries used, but for me didn't work without modifying the annotation of the constructor, replacing #Inject by #AssistedInject. With that, the code of the class that implements the interface looks like this.
public class CustomObject implements ICustomObject {
protected String name;
#AssistedInject
public CustomObject(#Assisted String name){
this.name = name;
}
}

Categories

Resources