Lombok - #Singular annotation not found - android

I am using Lombok for one of my apps.
I have a class declared with the annotation #Builder. The fields are annotated with #SerializedName("xxxxx") in order to support Gson.
However, one of the fields is a List so I would like to use the #Singular annotation for them, but looks like the lib doesn't know about this annotation.
#Builder
public class ProductForm {
#SerializedName("title") private String title;
#SerializedName("description") private String description;
#SerializedName("images") private List<ImageForm> imageFormList;
#SerializedName("active") private boolean active;
}
Does anyone know why?
Doc here

Using lombok 1.16.4 and your code (used #lombok.Builder not the deprecated one) I've no compile error when adding #lombok.Singular to imageFormList in your code.
So you probably forgot to import #lombok.Singular or used an old version of lombok.

Related

Define StringDef in kotlin

I'm trying to define a StringDef in kotlin:
#Retention(AnnotationRetention.SOURCE)
#StringDef(NORTH, SOUTH)
annotation class FilterType {
companion object {
const val NORTH = "NORTH"
const val SOUTH = "SOUTH"
}
}
I think something is wrong in the code above.
// I can send anything to this method, when using my kotlin stringDef
private fun takeString(#DirectionJava.Direction filterType: String) {
I want the kotlin equivalent of the java below:
public class DirectionJava {
public static final String NORTH = "NORTH";
public static final String SOUTH = "SOUTH";
#Retention(RetentionPolicy.SOURCE)
#StringDef({
NORTH,
SOUTH,
})
public #interface Direction {
}
}
Calling the java defined StringDef works from kotlin
// This works as expected, the Java-written string def
// restricts what I can pass to this method
private fun takeString(#DirectionJava.Direction filterType: String) {
Where have I gone wrong, how do you define a StringDef in Kotlin?
According to jetbrains issue, Lint check plugin for enumerated annotations in kotlin is under development and is not stable yet. Checking android support annotations such as #Nullable, #StringRes, #DrawableRes, #IntRange, ... (which are written in java) works fine and user defined enumerated annotations are not checked properly. So, it seems that we should define them in java then use in kotlin.
#StringDef now works if you define it inside a companion object. See:
https://stackoverflow.com/a/70672074/2465264
Also, consider using a Kotlin enum class instead since the performance issues have been fixed in ART (Android Runtime Machine), which most Android devices are now running.

Room not finding lombok generated constructor

I'm using lombok to generate constructors, getters and setters for my models. When i try to use lombok to generate the constructor for my entity class, I get this error
Error:(14, 8) error: Entities and Pojos must have a usable public
constructor. You can have an empty constructor or a constructor whose
parameters match the fields (by name and type).
Tried the following constructors but they failed to match:
Region(int,java.lang.String,java.lang.String) -> [param:arg0 -> matched
field:unmatched, param:arg1 -> matched field:unmatched, param:arg2 ->
matched field:unmatched]
but writing the constructor manually works. Can anyone help me figure out what's wrong?
My entity class is shown below
#Value
#Entity
public class Region {
#PrimaryKey
private int regionId;
private String name;
private String code;
}
Room version: 1.1.0
Lombok version: 1.16.20
The matching seems to fail because the constructor parameter names are not available at runtime.
Since version 1.16.20 lombok does not generate #ConstructorProperties annotations any more (which would carry those names).
Try adding lombok.anyConstructor.addConstructorProperties = true to your lombok.config, and lombok will generate a #ConstructorProperties annotation for your constructor. (See https://projectlombok.org/features/configuration for details on how to configure lombok.)
EDIT: The problem is the annotation processing during compilation. Both Room and lombok hook into javac as annotation processors, and they do not work nicely in combination. So at the moment, the only stable solution is to delombok first.
You can use the following setup:
#Entity
#Getter
#Setter
#AllArgsConstructor(onConstructor = #__({#Ignore}))
#NoArgsConstructor
public class Region {
#PrimaryKey
private int regionId;
private String name;
private String code;
}
This will make Room use the default constructor and set the value via the provided setters. Additionally you have a constructor that accepts all arguments for object instantiation, but will be ignored by Room.
Note: Object won't be immutable that way
Please try this as below with #Data annotation.
#Value
#Entity
#Data
public class Region {
#PrimaryKey
private int regionId;
private String name;
private String code;
}

AutoValue with GsonTypeAdapter in Kotlin

I am trying to integrate Kotlin in an existing android Java project. After making the changes in the build and adding Kotlin to the project I can't find a solution to my AutoValue classes that have GsonTypeAdapter there doesn't seem to be support for this.
#AutoValue
public abstract class MediaObject implements Parcelable {
public static TypeAdapter<MediaObject> typeAdapter(Gson gson) {
return new AutoValue_MediaObject.GsonTypeAdapter(gson);
}
#SerializedName("mimetype")
public abstract String getMimeType();
#SerializedName("url")
public abstract String getUri();
}
My Gson builder:
GsonBuilder().registerTypeAdapterFactory(new AutoValueGsonTypeAdapterFactory())
Any suggestions how to resolve this or what to use instead?
Just dont use it. If it is for Retrofit, you can just use .addConverterFactory(GsonConverterFactory.create()) and the kotlin data class.In your case, you need to remove MediaObject java class, and create data class:
data class MediaObject(
#SerializedName("mimetype")
val mimetypeString:String,
#SerializedName("url")
val uri:String)

how to combine Architecture Components with data binding on android?

I have developed app base on android data binding library: https://developer.android.com/topic/libraries/data-binding/index.html
class SignInViewModel extends BaseObservable {
#Bindable
public String getLogin() {
return login;
}
#Bindable
public String getPassword() {
return password;
}
}
and now I want to use ViewModelProviders from new library:
https://developer.android.com/topic/libraries/architecture/guide.html
SignInViewModel signInViewModel = ViewModelProviders.of(this).get(SignInViewModel.class);
How it combine? any idea? or should be combined these two libraries?
Edit
I change to:
class SignInViewModel extends ViewModel {
public ObservableField<String> login = new ObservableField<>("");
public ObservableField<String> password = new ObservableField<>("");
}
and now compiles, but question is: is it right way?
It's a known incompatibility. You can't extend BaseObservable and AndroidViewModel at the same time, so you can't use #Bindable making two-way data binding impossible*.
This will be fixed after arch components 1.0 final (on the data binding side).
*Edit: You can make your own ObservableViewModel: https://gist.github.com/JoseAlcerreca/4b66f9953d50b483d80e6b9ad7172685
Maybe this didn't exist when when the question was asked, but there is another option explained in this article: https://medium.com/google-developers/android-data-binding-observability-9de4ff3fe038
Basically instead of extending from BaseObservable you can implement android.databinding.Observable.
It's slightly more work as you need to also do the following:
Create this variable in your model class
private PropertyChangeRegistry registry = new PropertyChangeRegistry();
Implement the overriden methods like this
#Override
public void addOnPropertyChangedCallback(OnPropertyChangedCallback callback) {
registry.add(callback);
}
#Override
public void removeOnPropertyChangedCallback(OnPropertyChangedCallback callback) {
registry.remove(callback);
}
Replace all the "BR" calls with these:
registry.notifyChange(this, BR.bar);
Everything else works the same as extending from BaseObservable. So I think maybe this is the solution that Jose might have been alluding to which probably wasn't available back then. It seems to work.
Update: As Eugene Brusov has mentioned, you can now use LiveData with data binding. This is what I'm doing now and it's much easier with less boilerplate. See https://developer.android.com/topic/libraries/data-binding/architecture.
It's possible with Android Studio 3.1 Canary 6 (https://androidstudio.googleblog.com/2017/12/android-studio-31-canary-6-is-now.html):
You can now use a LiveData object as an observable field in data binding expressions. The ViewDataBinding class now includes a new setLifecycle method that you need to use to use to observe LiveData objects.
You can find more details and sample in this Medium post.
This can be also solved using a wrapper:
class SignInViewModelWrapper extends ViewModel {
public final SignInViewModel model = new SignInViewModel();
}
class SignInViewModel extends BaseObservable {
#Bindable
public String getLogin() {
return login;
}
#Bindable
public String getPassword() {
return password;
}
}
You can then get the view model like this:
SignInViewModel signInViewModel = ViewModelProviders.of(this).get(SignInViewModelWrapper.class).model;

Retrofit Android can't convert JSON response to model if the model's properties are private

I tried using Retrofit on Android and I encountered this problem.
I want to get data in JSON from an API and convert it into a model in my app.
This is my model
public class A {
private String property1;
private int property2;
//default constructor, getter and setter below
}
This is my service
public interface TestService {
#GET("/a")
void getA(Callback<A> callback);
}
When I retrieve the data using TestService, it won't return an error but it will return an empty class of A.
If I change the property of class A to public, then it will be converted to the right object A.
EDIT QUESTION
This is the JSON example that I want to convert into model A
{
"property1" : "content",
"property2" : 1
}
Use Expose annotation on your private fields if you are using GSON.
Like :
#Expose
private String property1;
#Expose
private int property2;
If you want to use a different name for your variables, you can try SerializedName annotation like :
#Expose
#SerializedName("property1")
private String p1;
#Expose
#SerializedName("property2")
private int p2;
I think that should work, if not post your complete "A" class.

Categories

Resources