Skip to content

Commit 22d0bbd

Browse files
committed
Release 0.34.3
Add builders to JsonPojoUtils Signed-off-by: Gopal S Akshintala <[email protected]>
1 parent 6ecda14 commit 22d0bbd

File tree

7 files changed

+160
-35
lines changed

7 files changed

+160
-35
lines changed

README.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ endif::[]
1616
:pmtemplates: src/integrationTest/resources/pm-templates
1717
:imagesdir: docs/images
1818
:prewrap!:
19-
:revoman-version: 0.34.2
19+
:revoman-version: 0.34.3
2020

2121
'''
2222

buildSrc/src/main/kotlin/Config.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@
66
* ************************************************************************************************
77
*/
88
const val GROUP_ID = "com.salesforce.revoman"
9-
const val VERSION = "0.34.2"
9+
const val VERSION = "0.34.3"
1010
const val ARTIFACT_ID = "revoman"
1111
const val STAGING_PROFILE_ID = "1ea0a23e61ba7d"

src/integrationTest/java/com/salesforce/revoman/input/json/JsonPojoUtils2Test.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,14 @@ class JsonPojoUtils2Test {
3131
@DisplayName("toJson: PQ Payload JSON -> PlaceQuoteInputRep -> PQ Payload JSON")
3232
void pqInputRepToPQPayloadJson() throws JSONException {
3333
final var pqAdapter = adapter(PlaceQuoteInputRepresentation.class);
34-
final var pqPayloadJsonFilePath = "json/pq-payload.json";
34+
final var expectedPQPayload = readFileInResourcesToString("json/pq-payload.json");
3535
final var pqInputRep =
36-
JsonPojoUtils.<PlaceQuoteInputRepresentation>jsonFileToPojo(
37-
PlaceQuoteInputRepresentation.class, pqPayloadJsonFilePath, List.of(pqAdapter));
36+
JsonPojoUtils.<PlaceQuoteInputRepresentation>jsonToPojo(
37+
PlaceQuoteInputRepresentation.class, expectedPQPayload, List.of(pqAdapter));
3838
assertThat(pqInputRep).isNotNull();
3939
final var pqPayloadJsonStr =
4040
JsonPojoUtils.pojoToJson(
4141
PlaceQuoteInputRepresentation.class, pqInputRep, List.of(pqAdapter));
42-
final var expectedPQPayload = readFileInResourcesToString(pqPayloadJsonFilePath);
4342
JSONAssert.assertEquals(expectedPQPayload, pqPayloadJsonStr, JSONCompareMode.STRICT);
4443
}
4544

@@ -48,8 +47,12 @@ void pqInputRepToPQPayloadJson() throws JSONException {
4847
void pqPayloadJsonToPQInputRep() {
4948
final var pqAdapter = adapter(PlaceQuoteInputRepresentation.class);
5049
final var pqInputRep =
51-
JsonPojoUtils.<PlaceQuoteInputRepresentation>jsonFileToPojo(
52-
PlaceQuoteInputRepresentation.class, "json/pq-payload.json", List.of(pqAdapter));
50+
JsonPojoUtils.jsonFileToPojo(
51+
JsonFile.<PlaceQuoteInputRepresentation>unmarshall()
52+
.pojoType(PlaceQuoteInputRepresentation.class)
53+
.jsonFilePath("json/pq-payload.json")
54+
.customAdapter(pqAdapter)
55+
.done());
5356
assertThat(pqInputRep).isNotNull();
5457
assertThat(pqInputRep.getPricingPref()).isEqualTo(PricingPreferenceEnum.System);
5558
assertThat(pqInputRep.getDoAsync()).isTrue();
@@ -63,8 +66,12 @@ void pqPayloadJsonToPQInputRep() {
6366
void unmarshallMarshallPqResponse() throws JSONException {
6467
final var pqResponseFromJson = readFileInResourcesToString("json/pq-response.json");
6568
final var pqResp =
66-
JsonPojoUtils.<PlaceQuoteOutputRepresentation>jsonToPojo(
67-
PlaceQuoteOutputRepresentation.class, pqResponseFromJson, List.of(new IDAdapter()));
69+
JsonPojoUtils.jsonToPojo(
70+
JsonString.<PlaceQuoteOutputRepresentation>unmarshall()
71+
.pojoType(PlaceQuoteOutputRepresentation.class)
72+
.jsonString(pqResponseFromJson)
73+
.customAdapter(new IDAdapter())
74+
.done());
6875
assertNotNull(pqResp);
6976
final var pqOutputRepJson =
7077
JsonPojoUtils.pojoToJson(

src/main/kotlin/com/salesforce/revoman/input/json/JsonPojoUtils.kt

Lines changed: 134 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,54 +15,93 @@ import com.squareup.moshi.JsonAdapter
1515
import com.squareup.moshi.JsonAdapter.Factory
1616
import io.vavr.control.Either
1717
import java.lang.reflect.Type
18+
import org.immutables.value.Value
1819

20+
/**
21+
* Parses a JSON file and converts it to a POJO of type [PojoT].
22+
*
23+
* @param pojoType The type of the POJO to be created
24+
* @param jsonFilePath The path to the JSON file
25+
* @param customAdapters A list of custom JSON adapters to be used during the parsing process
26+
* @param customAdaptersWithType A map of custom JSON adapters with their respective types
27+
* @param typesToSkip A set of types to be skipped during the parsing process
28+
* @param <PojoT> The type of the POJO to be created
29+
* @return the parsed POJO or null if the parsing fails
30+
*/
1931
@JvmOverloads
2032
fun <PojoT : Any> jsonFileToPojo(
2133
pojoType: Type,
2234
jsonFilePath: String,
2335
customAdapters: List<Any> = emptyList(),
2436
customAdaptersWithType: Map<Type, List<Either<JsonAdapter<Any>, Factory>>> = emptyMap(),
25-
typesToIgnore: Set<Class<out Any>> = emptySet()
37+
typesToSkip: Set<Class<out Any>> = emptySet()
2638
): PojoT? {
27-
val jsonAdapter =
28-
initMoshi<PojoT>(customAdapters, customAdaptersWithType, typesToIgnore, pojoType)
39+
val jsonAdapter = initMoshi<PojoT>(customAdapters, customAdaptersWithType, typesToSkip, pojoType)
2940
return jsonAdapter.fromJson(bufferFileInResources(jsonFilePath))
3041
}
3142

43+
fun <PojoT : Any> jsonFileToPojo(jsonFile: JsonFile<PojoT>): PojoT? =
44+
jsonFileToPojo(
45+
jsonFile.pojoType(),
46+
jsonFile.jsonFilePath(),
47+
jsonFile.customAdapters(),
48+
jsonFile.customAdaptersWithType(),
49+
jsonFile.typesToSkip()
50+
)
51+
3252
inline fun <reified PojoT : Any> jsonFileToPojo(
3353
jsonFilePath: String,
3454
customAdapters: List<Any> = emptyList(),
3555
customAdaptersWithType: Map<Type, List<Either<JsonAdapter<Any>, Factory>>> = emptyMap(),
36-
typesToIgnore: Set<Class<out Any>> = emptySet()
56+
typesToSkip: Set<Class<out Any>> = emptySet()
3757
): PojoT? =
3858
jsonFileToPojo(
3959
PojoT::class.java,
4060
jsonFilePath,
4161
customAdapters,
4262
customAdaptersWithType,
43-
typesToIgnore
63+
typesToSkip
4464
)
4565

66+
/**
67+
* A generic function that parses a JSON string into a POJO (Plain Old Java Object) of type PojoT.
68+
*
69+
* @param <PojoT> The type of the resulting POJO.
70+
* @param pojoType The class of the resulting POJO.
71+
* @param jsonStr The JSON string to be parsed.
72+
* @param customAdapters A list of custom adapters to be used during the parsing process.
73+
* @param customAdaptersWithType A map of custom adapters with their respective types.
74+
* @param typesToSkip A set of classes to be skipped during the parsing process.
75+
* @return The parsed POJO of type PojoT.
76+
*/
4677
@JvmOverloads
4778
fun <PojoT : Any> jsonToPojo(
4879
pojoType: Type,
4980
jsonStr: String,
5081
customAdapters: List<Any> = emptyList(),
5182
customAdaptersWithType: Map<Type, List<Either<JsonAdapter<Any>, Factory>>> = emptyMap(),
52-
typesToIgnore: Set<Class<out Any>> = emptySet()
83+
typesToSkip: Set<Class<out Any>> = emptySet()
5384
): PojoT? {
54-
val jsonAdapter =
55-
initMoshi<PojoT>(customAdapters, customAdaptersWithType, typesToIgnore, pojoType)
85+
val jsonAdapter = initMoshi<PojoT>(customAdapters, customAdaptersWithType, typesToSkip, pojoType)
5686
return jsonAdapter.fromJson(jsonStr)
5787
}
5888

89+
fun <PojoT : Any> jsonToPojo(jsonString: JsonString<PojoT>): PojoT? =
90+
jsonToPojo(
91+
jsonString.pojoType(),
92+
jsonString.jsonString(),
93+
jsonString.customAdapters(),
94+
jsonString.customAdaptersWithType(),
95+
jsonString.typesToSkip()
96+
)
97+
5998
inline fun <reified PojoT : Any> jsonToPojo(
6099
jsonStr: String,
61100
customAdapters: List<Any> = emptyList(),
62101
customAdaptersWithType: Map<Type, List<Either<JsonAdapter<Any>, Factory>>> = emptyMap(),
63-
typesToIgnore: Set<Class<out Any>> = emptySet()
102+
typesToSkip: Set<Class<out Any>> = emptySet()
64103
): PojoT? =
65-
jsonToPojo(PojoT::class.java, jsonStr, customAdapters, customAdaptersWithType, typesToIgnore)
104+
jsonToPojo(PojoT::class.java, jsonStr, customAdapters, customAdaptersWithType, typesToSkip)
66105

67106
/**
68107
* Generate a JSON string from a POJO object.
@@ -71,7 +110,7 @@ inline fun <reified PojoT : Any> jsonToPojo(
71110
* @param pojo The POJO object to be converted to JSON.
72111
* @param customAdapters A list of custom adapters for Moshi to use during the conversion.
73112
* @param customAdaptersWithType A map of custom adapters with their respective types.
74-
* @param typesToIgnore A set of classes to ignore during the conversion.
113+
* @param typesToSkip A set of classes to ignore during the conversion.
75114
* @param indent An optional string for pretty-printing the JSON output.
76115
* @param <PojoT> The type of the POJO object.
77116
* @return A JSON string or null if the input is null.
@@ -82,30 +121,107 @@ fun <PojoT : Any> pojoToJson(
82121
pojo: PojoT,
83122
customAdapters: List<Any> = emptyList(),
84123
customAdaptersWithType: Map<Type, List<Either<JsonAdapter<Any>, Factory>>> = emptyMap(),
85-
typesToIgnore: Set<Class<out Any>> = emptySet(),
124+
typesToSkip: Set<Class<out Any>> = emptySet(),
86125
indent: String? = " "
87126
): String? {
88-
val jsonAdapter =
89-
initMoshi<PojoT>(customAdapters, customAdaptersWithType, typesToIgnore, pojoType)
127+
val jsonAdapter = initMoshi<PojoT>(customAdapters, customAdaptersWithType, typesToSkip, pojoType)
90128
return (indent?.let { jsonAdapter.indent(indent) } ?: jsonAdapter).toJson(pojo)
91129
}
92130

131+
fun <PojoT : Any> pojoToJson(config: Pojo<PojoT>): String? =
132+
pojoToJson(
133+
config.pojoType(),
134+
config.pojo(),
135+
config.customAdapters(),
136+
config.customAdaptersWithType(),
137+
config.typesToSkip(),
138+
config.indent()
139+
)
140+
93141
inline fun <reified PojoT : Any> pojoToJson(
94142
pojo: PojoT,
95143
customAdapters: List<Any> = emptyList(),
96144
customAdaptersWithType: Map<Type, List<Either<JsonAdapter<Any>, Factory>>> = emptyMap(),
97-
typesToIgnore: Set<Class<out Any>> = emptySet(),
145+
typesToSkip: Set<Class<out Any>> = emptySet(),
98146
indent: String? = " "
99147
): String? =
100-
pojoToJson(PojoT::class.java, pojo, customAdapters, customAdaptersWithType, typesToIgnore, indent)
148+
pojoToJson(PojoT::class.java, pojo, customAdapters, customAdaptersWithType, typesToSkip, indent)
101149

102150
@SuppressWarnings("kotlin:S3923")
103151
private fun <PojoT : Any> initMoshi(
104152
customAdapters: List<Any> = emptyList(),
105153
customAdaptersWithType: Map<Type, List<Either<JsonAdapter<Any>, Factory>>> = emptyMap(),
106-
typesToIgnore: Set<Class<out Any>> = emptySet(),
154+
typesToSkip: Set<Class<out Any>> = emptySet(),
107155
pojoType: Type
108156
): JsonAdapter<PojoT> {
109-
val moshiBuilder = buildMoshi(customAdapters, customAdaptersWithType, typesToIgnore)
157+
val moshiBuilder = buildMoshi(customAdapters, customAdaptersWithType, typesToSkip)
110158
return moshiBuilder.build().adapter(pojoType)
111159
}
160+
161+
@PojoConfig
162+
@Value.Immutable
163+
internal interface PojoDef<PojoT> {
164+
fun pojoType(): Type
165+
166+
fun pojo(): PojoT
167+
168+
fun customAdapters(): List<Any>
169+
170+
fun customAdaptersWithType(): Map<Type, List<Either<JsonAdapter<Any>, Factory>>>
171+
172+
fun typesToSkip(): Set<Class<out Any>>
173+
174+
@Value.Default fun indent(): String = " "
175+
}
176+
177+
@Target(AnnotationTarget.CLASS)
178+
@Retention(AnnotationRetention.SOURCE)
179+
@Value.Style(
180+
typeImmutable = "*",
181+
typeAbstract = ["*Def"],
182+
builder = "marshall",
183+
build = "done",
184+
depluralize = true,
185+
add = "*",
186+
put = "*",
187+
with = "override*",
188+
visibility = Value.Style.ImplementationVisibility.PUBLIC,
189+
)
190+
private annotation class PojoConfig
191+
192+
internal interface JsonConfig<PojoT> {
193+
fun pojoType(): Type
194+
195+
fun customAdapters(): List<Any>
196+
197+
fun customAdaptersWithType(): Map<Type, List<Either<JsonAdapter<Any>, Factory>>>
198+
199+
fun typesToSkip(): Set<Class<out Any>>
200+
}
201+
202+
@ConfigForJson
203+
@Value.Immutable
204+
internal interface JsonFileDef<PojoT> : JsonConfig<PojoT> {
205+
fun jsonFilePath(): String
206+
}
207+
208+
@ConfigForJson
209+
@Value.Immutable
210+
internal interface JsonStringDef<PojoT> : JsonConfig<PojoT> {
211+
fun jsonString(): String
212+
}
213+
214+
@Target(AnnotationTarget.CLASS)
215+
@Retention(AnnotationRetention.SOURCE)
216+
@Value.Style(
217+
typeImmutable = "*",
218+
typeAbstract = ["*Def"],
219+
builder = "unmarshall",
220+
build = "done",
221+
depluralize = true,
222+
add = "*",
223+
put = "*",
224+
with = "override*",
225+
visibility = Value.Style.ImplementationVisibility.PUBLIC,
226+
)
227+
private annotation class ConfigForJson

src/main/kotlin/com/salesforce/revoman/internal/json/MoshiReVoman.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import com.salesforce.revoman.internal.json.adapters.EpochAdapter
1414
import com.salesforce.revoman.internal.json.adapters.TypeAdapter
1515
import com.salesforce.revoman.internal.json.adapters.UUIDAdapter
1616
import com.salesforce.revoman.internal.json.factories.CaseInsensitiveEnumAdapter
17-
import com.salesforce.revoman.internal.json.factories.IgnoreUnknownFactory
17+
import com.salesforce.revoman.internal.json.factories.SkipTypesFactory
1818
import com.squareup.moshi.JsonAdapter
1919
import com.squareup.moshi.JsonAdapter.Factory
2020
import com.squareup.moshi.Moshi
@@ -81,7 +81,7 @@ internal fun buildMoshi(
8181
}
8282
}
8383
if (typesToIgnore.isNotEmpty()) {
84-
moshiBuilder.add(IgnoreUnknownFactory(typesToIgnore))
84+
moshiBuilder.add(SkipTypesFactory(typesToIgnore))
8585
}
8686
return moshiBuilder
8787
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ import com.squareup.moshi.Moshi
1515
import com.squareup.moshi.Types
1616
import java.lang.reflect.Type
1717

18-
internal class IgnoreUnknownFactory(private val typesToIgnore: Set<Class<out Any>>) : Factory {
18+
internal class SkipTypesFactory(private val typesToSkip: Set<Class<out Any>>) : Factory {
1919
override fun create(type: Type, annotations: Set<Annotation?>, moshi: Moshi): JsonAdapter<*>? {
2020
val rawType: Class<*> = Types.getRawType(type)
21-
return if (typesToIgnore.contains(rawType)) {
21+
return if (typesToSkip.contains(rawType)) {
2222
object : JsonAdapter<Type>() {
2323
override fun fromJson(reader: JsonReader): Type? {
2424
reader.skipValue()

src/test/java/com/salesforce/revoman/input/json/JsonPojoUtilsTest.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,11 @@ void compositeGraphSuccessResponseMarshallUnmarshall() throws JSONException {
4343
assertThat(successGraphResponse.getGraphs().get(0)).isInstanceOf(SuccessGraph.class);
4444
final var successGraphResponseUnmarshalled =
4545
JsonPojoUtils.pojoToJson(
46-
CompositeGraphResponse.class,
47-
successGraphResponse,
48-
List.of(CompositeGraphResponse.ADAPTER));
46+
Pojo.marshall()
47+
.pojoType(CompositeGraphResponse.class)
48+
.pojo(successGraphResponse)
49+
.customAdapter(CompositeGraphResponse.ADAPTER)
50+
.done());
4951
JSONAssert.assertEquals(
5052
graphSuccessResponseJsonStr, successGraphResponseUnmarshalled, JSONCompareMode.STRICT);
5153
}

0 commit comments

Comments
 (0)