gabrielittner / auto-value-cursor Goto Github PK
View Code? Open in Web Editor NEWAutoValue extension to create an AutoValue object from a Cursor
License: Apache License 2.0
AutoValue extension to create an AutoValue object from a Cursor
License: Apache License 2.0
Add support to ignore fields in the fromCursor and toContentValues implementation.
Instances of ColumnTypeAdapter
cannot be provided dependencies via constructor since the generated code simply creates an instance of the type adapter using the default constructor.
This should be similar to #24 and #25
When using foreign keys you can't put 0 as an ID value and need to use putNull instead.
Current workaround would be providing another contentValues method as described in the comments of #25
abstract ContentValues toCompleteContentValues();
public ContentValues toContentValues() {
ContentValues contentValues = toCompleteContentValues();
contentValues.remove(TableEvent.COLUMN_ID);
if (subjectId() == 0) {
contentValues.putNull(TableEvent.COLUMN_SUBJECT_ID);
}
return contentValues;
}
As with going from a Cursor to a custom object type, if there a way to specify how to map the custom object type to a content value?
Cheers
After upgrading to 0.5.0 I ran into error with Dagger2 as described in #32 and resolved it by upgrading Dagger2 to version 2.4.
Now classes implementing the new ColumnTypeAdapter are valid in generated source code but fail at runtime:
Any ideas?
If a non-primitive field has been annotated as nullable, then createFromCursor(Cursor cursor)
should check cursor.isNull()
, and if true, return a null
for that field.
I discovered this issue when inserting null
for an Integer
field using ContentValues.putNull(String key)
while later when retrieving the row, createFromCursor
returns a 0
.
Related SO questions:
http://stackoverflow.com/questions/8063768
http://stackoverflow.com/questions/18054182/
To use AutoValue builders with optional properties, you have to use Optional
(from either Java 8 or Guava); see here: https://github.com/google/auto/blob/master/value/userguide/builders-howto.md#optional
If we try to use Optional
properties with the auto-value-cursor extension, we get this result:
Property "PROPERTY" has type "com.google.common.base.Optional<java.lang.String>" that can't be read from Cursor.
It would make sense to coalesce an Optional
without a value to SQL NULL
(and vice-versa).
When using auto-value-cursor 2.0.0, it raise following error
Caused by: java.lang.ClassNotFoundException: com.gabrielittner.auto.value.util.Property
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
There are no tests for the generation of Func1<Cursor, T>
.
After google/auto#673 , I tried to enable incremental build on my sample project that is using auto-value and its extensions.
https://github.com/ganadist/auto-value-cursor-incremental-test/blob/master/app/build.gradle#L36-L43
But when auto-value-cursor compiler is enabled by kapt, gradle prints following log.
> Task :app:kaptDebugKotlin
[WARN] Incremental annotation processing requested,
but support is disabled because the following processors are not incremental:
com.google.auto.value.processor.AutoValueProcessor (DYNAMIC).
Hi,
I've just started using the lib and was wondering if it's possible to take an auto-value object and essentially perform the opposite of this library?
Would make working with cursors that one step easier!
Cheers
On Android, _id
columns are usually set as primary keys (INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
).
When I want to read them:
@ColumnName("_id") public abstract int getId();
Then Auto-Value-Cursor (and auto-value, for that matter) insists on creating a constructor parameter.
As a workaround, I was able to use @Nullable Integer
and pass null
to the constructor, but that reads incorrect.
I have already added gradle dependencies as per your provided instruction, but @autovalue dependencies not fixed. @ColumnName("name") working properly, but issues with @autovalue. Please help me. Thanks
Build Environment:
Android studio 2.2.2
distributionUrl=https://services.gradle.org/distributions/gradle-2.14.1-all.zip
I would need, in some cases, to fill in a given ContentValues and return it, instead of creating a new one.
e.g. public abstract ContentValues fillContentValues(ContentValues values);
Could it be possible to add this to the library?
Thanks!
This is a duplicate of #61. It was already closed and I added a comment getting no answer, so I post it as a new issue to make sure it can be reviewed. Thanks a lot.
I am trying to to follow the approach you suggested, but I am having issues with the types.
I have implemented a generic ColumnTypeAdapter:
public abstract class IgnoreColumnAdapter implements ColumnTypeAdapter {
public final T fromCursor(Cursor cursor, String columnName) {
return null;
}
public final void toContentValues(ContentValues values, String columnName, T value) {
}
}
Having this class:
public class User {
// Column needs to be ignored
public abstract UserCredentials userCredentials();
}
I have to create an specific class IgnoreUserCredentialsAdapter extends IgnoreColumnAdapter to ensure the generated code in fromCursor() has the expected type.
We have many types we would like to ignore. Is there a way to achieve this without creating an specific type for each of them?
Thanks a lot!
I have a class with such fields:
@ColumnName(SearchManager.SUGGEST_COLUMN_TEXT_1)
public abstract String text1();
@Nullable
@ColumnName(SearchManager.SUGGEST_COLUMN_TEXT_2)
public abstract String text2();
Generated code for these two fields:
String text1 = cursor.getString(cursor.getColumnIndexOrThrow("suggest_text_1"));
int text2ColumnIndex = cursor.getColumnIndexOrThrow("suggest_text_2");
String text2 = cursor.isNull(text2ColumnIndex) ? null : cursor.getString(text2ColumnIndex);
And now when I haven't column suggest_text_2
in my cursor it will throw an exception.
The solution should be:
String text1 = cursor.getString(cursor.getColumnIndexOrThrow("suggest_text_1"));
int text2ColumnIndex = cursor.getColumnIndex("suggest_text_2");
String text2 = (text2ColumnIndex == -1 || cursor.isNull(text2ColumnIndex)) ? null : cursor.getString(text2ColumnIndex);
Do you support or plan to support builders? See attached sample value class and stack trace. Not talking about converting to/from a builder, albeit that would be nice as well (but is probably not supported by AutoValue's extension mechanism).
package info.mschmitt.contacts.database.entities;
import android.database.Cursor;
import com.google.auto.value.AutoValue;
import javax.annotation.Nullable;
/**
* @author Matthias Schmitt
*/
@AutoValue
public abstract class Contact {
Contact() {
}
public static Builder builder() {
return new AutoValue_Contact.Builder();
}
public static Contact create(Cursor cursor) {
return AutoValue_Contact.createFromCursor(cursor);
}
// // if your project includes RxJava the extension will generate a Func1<Cursor, User> for you
// public static Func1<Cursor, Contact> mapper() {
// return AutoValue_Contact.MAPPER;
// }
// // Optional: When you include an abstract method that returns ContentValues and doesn't have
// // any parameters the extension will implement it for you
// abstract ContentValues toContentValues();
public abstract Builder toBuilder();
public abstract long id();
@Nullable
public abstract String name();
@Nullable
public abstract String email();
@AutoValue.Builder
public abstract static class Builder {
public abstract Contact build();
public abstract Builder id(long id);
public abstract Builder name(@Nullable String name);
public abstract Builder email(@Nullable String email);
}
}
Error:(13, 17) error: @AutoValue processor threw an exception: java.lang.IllegalArgumentException: Property toBuilder has type info.mschmitt.contacts.database.entities.Contact.Builder that can't be read from Cursor.
at com.gabrielittner.auto.value.cursor.AutoValueCursorExtension.createReadMethod(AutoValueCursorExtension.java:135)
at com.gabrielittner.auto.value.cursor.AutoValueCursorExtension.generateClass(AutoValueCursorExtension.java:75)
at com.google.auto.value.processor.AutoValueProcessor.processType(AutoValueProcessor.java:424)
at com.google.auto.value.processor.AutoValueProcessor.process(AutoValueProcessor.java:143)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:794)
...
I have seen that you added this in a recent commit and I was wondering when you will make a new release available on Maven.
For example, I have a couple of objects that contain a Date field and I was wondering if there could be a way to create only one DateCursorAdapter which would use the column name given in the annotation @ColumnName, in order to not create a class for each field that is a Date and has different column name.
This means that I would need to somehow receive the value from @ColumnName in order to use it when processing the cursor.
Would be nice to apply this logic to ValuesAdapter as well.
Thanks!
Our app makes really heavy use of BigDecimal
in the models - it would be great if instead of having to copy/paste @ColumnAdapter(BigDecimalCursorAdapter.class)
on each BigDecimal field that we could just register it once globally, and that ColumnAdapter is invoked for all fields of the specified type.
I'm not super-familiar with the technicals of writing annotation processors, so I'm not 100% sure if this is possible/what it would look like. But it would be great if we could do something similar to Gson's type adapters:
AutoValueCursor.registerColumnAdapter(BigDecimal.class, new BigDecimalCursorAdapter());
For example, I have an object Vehicle which contains a field of type Price with its ColumnTypeAdapter and another field of type Owner with its ColumnTypeAdapter. I want to declare these adapters in the corresponding classes and use them both in the Vehicle class.
The problem is that when this extension generates the method createFromCursor(Cursor) it declares the columnAdapter variables with the same name and I receive the error:
Error:(26, 33) error: variable columnAdapter is already defined in method createFromCursor(Cursor)
and the generated code:
...
Price.ColumnAdapter columnAdapter = new Price.ColumnAdapter();
Owner.ColumnAdapter columnAdapter = new Owner.ColumnAdapter();
...
e.g.
@autovalue
public class Vehicle {
@ColumnAdapter(Price.ColumnAdapter.class)
Price price();
@ColumnAdapter(Owner.ColumnAdapter.class)
Owner owner();
}
@autovalue
public class Price {
....
public static class ColumnAdapter implements ColumnTypeAdapter {
....
}
}
@autovalue
public class Owner {
....
public static class ColumnAdapter implements ColumnTypeAdapter {
....
}
}
From my testing, auto-value-parcel already handles this case.
Can you make the extension support identical names?
Thanks!
Diana
is there a way to set a default value for the created object if cursor column was null?
like type adapter in autoValueGson.
Is there any annotation or something to add to a property in order for it to be left out when building toContentValues?
I would need this for the Ids that are autoincremented primary keys.
Thanks!
Can't seem to get the Code generation to work using the example on the readMe, I'm using the the latest snapshot (see gradle below). However still cant seem to get the createFromCursor method to be auto-generated.
allprojects {
repositories {
jcenter()
maven {
url {
"https://oss.sonatype.org/content/repositories/snapshots"
}
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.3.0'
compile "io.reactivex:rxandroid:1.1.0"
compile "io.reactivex:rxjava:1.1.0"
//Dagger
apt 'com.google.dagger:dagger-compiler:2.2' /* Dagger */
compile 'com.google.dagger:dagger:2.2' /* Dagger */
provided 'javax.annotation:jsr250-api:1.0' /* Dagger */
// AutoValue and AutoParcel
provided "com.google.auto.value:auto-value:1.2"
apt "com.google.auto.value:auto-value:1.2"
apt 'com.gabrielittner.auto.value:auto-value-cursor:0.4.1-SNAPSHOT'
// if you need the @ColumnName or @CursorAdapter annotations also include this:
provided 'com.gabrielittner.auto.value:auto-value-cursor-annotations:0.4.0'
apt 'com.ryanharter.auto.value:auto-value-parcel:0.2.1'
}
I'm using the direct example from the ReadMe seen here. I don't believe I missed anything.
@AutoValue public abstract class User {
abstract String id();
abstract String name();
// use the annotation if column name and field name aren't the same
@ColumnName("email_address") abstract String email();
public static User create(Cursor cursor) {
return AutoValue_User.createFromCursor(cursor);
}
// if your project includes RxJava the extension will generate a Func1<Cursor, User> for you
public static Func1<Cursor, User> mapper() {
return AutoValue_User.MAPPER;
}
// Optional: When you include an abstract method that returns ContentValues and doesn't have
// any parameters the extension will implement it for you
abstract ContentValues toContentValues();
}
Hi Gabriel,
I'm having some issue with a couple of methods that are not generated. Here is my model:
@AutoValue
public abstract class CatapushFile implements Parcelable {
public abstract String id();
@ColumnName("message_id")
public abstract String messageId();
public abstract String filename();
@ColumnName("local_uri")
@Nullable
public abstract String localUri();
@ColumnName("remote_uri")
public abstract String remoteUri();
@ColumnName("thumbnail_uri")
public abstract String thumbnailUri();
public abstract String type();
public abstract long size();
public abstract String hash();
public static Builder builder() {
return new AutoValue_CatapushFile.Builder()
.id(UUID.randomUUID().toString());
}
public abstract CatapushFile withLocalUri(String localUri);
@AutoValue.Builder
public abstract static class Builder {
[...]
}
public static CatapushFile create(Cursor cursor) {
return AutoValue_CatapushFile.createFromCursor(cursor);
}
public static Func1<Cursor, CatapushFile> mapper() {
return AutoValue_CatapushFile.MAPPER;
}
abstract ContentValues toContentValues();
}
This is what I get after the build:
abstract class $$AutoValue_CatapushFile extends $$$AutoValue_CatapushFile {
static final Func1<Cursor, CatapushFile> MAPPER = new Func1<Cursor, CatapushFile>() {
@Override
public AutoValue_CatapushFile call(Cursor c) {
return createFromCursor(c);
}
};
$$AutoValue_CatapushFile(String id, String messageId, String filename, String localUri, String remoteUri, String thumbnailUri, String type, long size, String hash) {
super(id, messageId, filename, localUri, remoteUri, thumbnailUri, type, size, hash);
}
static AutoValue_CatapushFile createFromCursor(Cursor cursor) {
String id = cursor.getString(cursor.getColumnIndexOrThrow("id"));
String messageId = cursor.getString(cursor.getColumnIndexOrThrow("message_id"));
String filename = cursor.getString(cursor.getColumnIndexOrThrow("filename"));
int localUriColumnIndex = cursor.getColumnIndexOrThrow("local_uri");
String localUri = cursor.isNull(localUriColumnIndex) ? null : cursor.getString(localUriColumnIndex);
String remoteUri = cursor.getString(cursor.getColumnIndexOrThrow("remote_uri"));
String thumbnailUri = cursor.getString(cursor.getColumnIndexOrThrow("thumbnail_uri"));
String type = cursor.getString(cursor.getColumnIndexOrThrow("type"));
long size = cursor.getLong(cursor.getColumnIndexOrThrow("size"));
String hash = cursor.getString(cursor.getColumnIndexOrThrow("hash"));
return new AutoValue_CatapushFile(id, messageId, filename, localUri, remoteUri, thumbnailUri, type, size, hash);
}
}
mapper()
and toContentValues()
methods are missing.
This is a snippet of my build.gradle
:
// Dependency Injection
apt 'com.squareup:javapoet:1.7.0'
compile "com.google.dagger:dagger:2.4"
apt "com.google.dagger:dagger-compiler:2.4"
// Annotations
provided 'javax.annotation:jsr250-api:1.0'
provided 'org.glassfish:javax.annotation:10.0-b28'
compile "com.android.support:support-annotations:${ANDROID}"
compile 'org.jetbrains:annotations:13.0'
provided "com.google.auto.value:auto-value:1.2"
apt "com.google.auto.value:auto-value:1.2"
apt 'com.ryanharter.auto.value:auto-value-parcel:0.2.2'
apt 'com.gabrielittner.auto.value:auto-value-cursor:0.5.1-SNAPSHOT'
compile 'com.gabrielittner.auto.value:auto-value-cursor-annotations:0.5.1-SNAPSHOT'
apt 'com.gabrielittner.auto.value:auto-value-with:0.1.4'
Am I missing something? Any help, please?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.