google / google/gson

Cannot have mixed type fields

Open
#1,369 0 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Java
Stars
24.2k
Forks
4.5k
Avg merge
6d 4h
Merged PRs (30d)
12

Description

I'm currently faced with a JSON model that has a field whose type depends on the direction (serialization vs deserialization).

I have the following class:

```
data class MyModel(val id: String?) {
@JsonExcludeSerialize
@SerializedName("data") private var _dataIn: List = listOf()

@JsonExcludeDeserialize
@SerializedName("data") private var _dataOut: List = listOf()
}
```

I also created following exclusion strategy and annotations:

```
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
annotation class JsonExcludeSerialize

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
annotation class JsonExcludeDeserialize

class JsonExcludeStrategy(private val direction: JsonExcludeStrategy.Direction) : ExclusionStrategy {
enum class Direction { SERIALIZE, DESERIALIZE }

private fun annotationMeansSkip(annotation: Annotation): Boolean {
if (direction == Direction.SERIALIZE && annotation is JsonExcludeSerialize) return true
if (direction == Direction.DESERIALIZE && annotation is JsonExcludeDeserialize) return true
return false
}

override fun shouldSkipField(f: FieldAttributes): Boolean {
return f.annotations.firstOrNull { annotationMeansSkip(it) } != null
}

override fun shouldSkipClass(clazz: Class<*>): Boolean {
return clazz.annotations.firstOrNull { annotationMeansSkip(it) } != null
}
}
```

And registered with:

```
gson = GsonBuilder()
.addSerializationExclusionStrategy(JsonExcludeStrategy(JsonExcludeStrategy.Direction.SERIALIZE))
.addDeserializationExclusionStrategy(JsonExcludeStrategy(JsonExcludeStrategy.Direction.DESERIALIZE))
.create()
```

Unfortunately I hit the following exception:

```
java.lang.IllegalArgumentException: class com.me.app.MyModel declares multiple JSON fields named data
```

This shouldn't be an issue since one `data` field is used for serialization and the other is used for deserialization.

I traced the issue to the line 168 in the following block:

https://github.com/google/gson/blob/master/gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java#L163:L170

Since all `BoundField`s are indexed by their json field name `LinkedHashMap.put` will return the previously registered `data` field when the second comes up and raise an exception. Maybe a `LinkedHashSet` could be used instead with a custom `equalTo` implementation on `BoundField` to determine collision.

I am not versed enough in Java to submit a pull request hence the long details and possible solution above.

Thanks for considering and in the mean time if anybody has a workaround I would appreciate it.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.