Comments (15)
@LouisCAD I would prefer to not have support for that unless there is a very compelling argument. I don't think we should consider properties declared outside the primary constructor to be a part of that class. This is similar to how Kotlin treats data classes (it doesn't include those properties in hashCode
, equals
or toString
) which to me means that Kotlin's intentions are for those properties to be considered computed or cached.
One "hack" you could potentially use is to have two constructors like this:
@JsonSerializable
data class Foo(val prop1: String) {
var prop2: String? = null
@KotshiConstructor
constructor(prop1: String, prop2: String?) : this(prop1) {
this.prop2 = prop2
}
}
Generated adapter:
public final class KotshiFooJsonAdapter extends JsonAdapter<Foo> {
private static final JsonReader.Options OPTIONS = JsonReader.Options.of(
"prop1",
"prop2");
public KotshiFooJsonAdapter() {
}
@Override
public void toJson(JsonWriter writer, Foo value) throws IOException {
if (value == null) {
writer.nullValue();
return;
}
writer.beginObject();
writer.name("prop1");
writer.value(value.getProp1());
writer.name("prop2");
writer.value(value.getProp2());
writer.endObject();
}
@Override
public Foo fromJson(JsonReader reader) throws IOException {
if (reader.peek() == JsonReader.Token.NULL) {
return reader.nextNull();
}
reader.beginObject();
String prop1 = null;
String prop2 = null;
while (reader.hasNext()) {
switch (reader.selectName(OPTIONS)) {
case 0: {
if (reader.peek() == JsonReader.Token.NULL) {
reader.nextNull();
} else {
prop1 = reader.nextString();
}
continue;
}
case 1: {
if (reader.peek() == JsonReader.Token.NULL) {
reader.nextNull();
} else {
prop2 = reader.nextString();
}
continue;
}
case -1: {
reader.nextName();
reader.skipValue();
continue;
}
}
}
reader.endObject();
StringBuilder stringBuilder = null;
if (prop1 == null) {
stringBuilder = KotshiUtils.appendNullableError(stringBuilder, "prop1");
}
if (stringBuilder != null) {
throw new NullPointerException(stringBuilder.toString());
}
return new Foo(
prop1,
prop2);
}
}
from kotshi.
So, to clarify: my use case is to ignore property with Room, while still getting it from the JSON.
Your second constructor trick worked perfectly, and while I had to add a bit more boilerplate for the constructor delegation considering the high number of parameters, it enabled me to separate the Room annotations (@Embedded
) that are seen in the main constructor from the Kotshi/Moshi ones (@Json(name= "…")
) that are seen in the secondary one.
It makes it clearer what is persisted in DB and what is got from the remote API.
Thanks for your help, again!
I'm closing this issue now that this limitation is documented.
from kotshi.
You are correct in assuming there is no support for this and it is by design. No non constructor property can be used with Kotshi, it would promote a bad design IMO (having mutable data-classes) plus it leads to many edge cases.
from kotshi.
Sometimes, you don't have control on what the remote server is sending, and being able to have such "transient" property helps.
Don't you think the design should be edited to support non constructor properties like Moshi for java and moshi-kotlin for Kotlin do?
This is preventing me to complete my kotshi migration, with no workaround since the field must not be part of the data class generated code, and I assume this issue will be faced by other people migrating to kotshi, especially from Java (which is not my case, could start this project 100% Kotlin)
from kotshi.
I don't think so, I compare Kotshi to AutoValue and not the standard reflection adapter.
If you don't want it to be in hashCode and equals you could easily create a subclass to List< SupportTicket>
that returns 0
for the hash code and true
for equals. Or you could provide your own implementation of hashCode and equals.
It's a bit too tricky to support non constructor parameters at this time since delegates, lateinits and computed properties would have to be handled. I just rather see that some other solution is found.
from kotshi.
Also, I don't think this library should limit what we can do with our data classes more than Kotlin and the underlying Moshi of this library don't prohibit mutable values, and we've had mutable fields and properties for years with Java, which many projects took advantage of, among which some didn't suffer from the potential mutability issues.
I know mutable properties are risky, but I think preventing to use them in kotshi would do more harm than good because there can be good use cases for using non constructor properties from JSON, and these use cases are currently prohibited from using kotshi, which means an incompressible and unproguardable 1MB toll if you want to stick to Moshi.
from kotshi.
Wouldn't handling computed properties just mean calling the getter or setter?
Anyway, thanks for the subclass tip, will try!
from kotshi.
Well, most of the time you wouldn't want computed properties in your JSON since they are just that, computed.
It is true that neither Moshi nor Kotlin prevents the use of mutable classes but I think it's reasonable to have that limitation. There are workarounds for your problem, even though I think that skipping properties in hash code and equals is very risky I'm sure you have your reasons for it.
I don't think it's unreasonable to say that we only support the primary properties of a data class. It doesn't really matter if they are mutable or not as long as they are in the primary constructor.
from kotshi.
My use case is to not leak the inconsistent remote API into the app's API. The supportTickets
non constructor example property is something I put in a separate table in Room, so I want it to feel unsafe API design wise because I only deal with it at API request time, and not after, especially not after it's persisted in the Room DB.
I think I'll have to integrate it in the constructor for now since implementing List
and overriding hashcode and equals safely is not trivial, and it doesn't prevent the property from appearing in the data class copy()
.
from kotshi.
from kotshi.
It feels like this is a very specific use case. Why not just have a separate data class for what you receive from the server and what you persist? This would give your much more flexibility and you wouldn't have these problems any more.
Out of curiosity, why don't you want the property to be a part of hash code and equals?
from kotshi.
@ansman I remember now that I tried to put it back in the constructor, my issues is not with hashCode and equals, nor copy, (although I prefer not include it in) but it is a compilation error.
Room compiler can't ignore constructor parameters, so putting it outside was my solution. EDIT: Here's an issue I created for the limitation in Room: https://issuetracker.google.com/issues/70762008
For the API & DB model separation, I find it counterproductive (both from programming and performance point of views) to copy the same model for just an optional property when everything else is how I need to save it in the DB.
from kotshi.
Whatever happens, I think this should be listed under the Limitations part of the README as long as it is. Should I make a PR?
from kotshi.
I cloned the repo on my computer and started digging through the code to understand what it'd mean to remove this limitation. It looks a bit hard, especially for a code generation beginner like me, but feasible.
@ansman If I succeed in adding support for non constructor properties, would it get merged assuming the code is clean enough according to your standards?
from kotshi.
I understand your point of sticking to the data class philosophy and approve the README clarifications.
My workaround to complete the migration has been to copy paste the generated adapter, (converting it to Kotlin in the process), then adding the missing bits I needed.
Your workaround seems better. I have to check it works with Room compiler, thanks for your help.
from kotshi.
Related Issues (20)
- Don't add @Generated if the annotation does not exist HOT 1
- invalid code in xxxJsonAdapter generated with @JsonSerializable HOT 1
- Unable to build project with Jetifier enabled (2.0.2) HOT 1
- Investigate support for inline classes HOT 1
- all of the objects have one companion object in ram ?!!?! HOT 3
- Migrate to KSP
- Implementation documentation or sample app? HOT 5
- Kotlin 1.5 borked HOT 3
- Generated annotation not found when compiling against Java 11 HOT 10
- Alternative annotation for custom names HOT 9
- v2.9.0: Excess code generated in adapters (Kapt) HOT 4
- Possible race condition in KSP factory generation HOT 12
- 2.10.0 KSP generates non-compilable classes when nullable field with same name as class and default value HOT 4
- 2.10.1 KSP generated adapters have trouble with generic typealiases when there is a default value HOT 3
- Serialisation issue is sallowed HOT 2
- Unresolved reference: KotshiAppJsonAdapterFactory HOT 2
- KotshiApplicationJsonAdapterFactory does not have a companion object HOT 6
- Usage with JVM 11 HOT 3
- Backend Internal error HOT 5
- [Intermittent] No JsonAdapter is getting created for random response classes after migrating to ksp from kapt HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from kotshi.