Converting Object to JSON and JSON to Object in PHP, (Library Like Gson for Java)

Converting Object to JSON and JSON to Object in PHP, (library like Gson for Java)

This should do the trick!

// convert object => json
$json = json_encode($myObject);

// convert json => object
$obj = json_decode($json);

Here's an example

$foo = new StdClass();
$foo->hello = "world";
$foo->bar = "baz";

$json = json_encode($foo);
echo $json;
//=> {"hello":"world","bar":"baz"}

print_r(json_decode($json));
// stdClass Object
// (
// [hello] => world
// [bar] => baz
// )

If you want the output as an Array instead of an Object, pass true to json_decode

print_r(json_decode($json, true));
// Array
// (
// [hello] => world
// [bar] => baz
// )

More about json_encode()

See also: json_decode()

Converting JSON list as different Java Objects in GSON

You can have following classes

class Question{
questionId; //specify data type
courseId;
}
class Choice{
choiceId;
questionId;
}

Then you can define one more class which will hold all the three member variables

class Extract{
Question question;
List<String> tags;
List<Choice> choices;
}

Then you can pass this Extract class to fromJson method like

List<Extract> result = gson.fromJson(jsonString, new TypeToken<List<Extract>>(){}.getType());

How to convert object format to json format in php

You shoud reindex result before json_encode

$event = array_values(array_unique($array_event));

Plain Old PHP object to json conversion

You can use json_encode()

Example:

$arr = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5);
echo json_encode($arr);

Output:

{"a":1,"b":2,"c":3,"d":4,"e":5}

To do the opposite, you can use json_decode()

JSON to Java Object without creating class (PHP way)

Read it into a map using Jackson then you can access whatever data you want. For instance, if your json looks like this

{ "name":"blah",
"address": {
"line1": "1234 my street",
"city": "my city",
"state": "my state"
}
}

Then you could:

ObjectMapper mapper = new ObjectMapper();
Map<String, Object> mystuff = mapper.readValue( jsonString, Map.class );
String name = (String)mystuff.get("name");
String city = ((Map<String, Object>)mystuff.get( "address" )).get( "city" );

How to work around a quirky JSON API with Retrofit2 and GSON converter

You don't need that many type adapters since you can merge the common deserialization logic into type adapters designed for each problematic literal type (just like you posted in your question) encountered from that back end.

Type adapters created independently, not in type adapter factories, usually fit simple cases. Factories provide access to the shared context Gson instance (the one you configure and then use) and provide a concrete type to build a type adapter with (this is where "T.class" can be worked around).

public abstract class AbstractQuirkyTypeAdapterFactory<T, C>
implements TypeAdapterFactory {

protected abstract boolean supports(@Nonnull TypeToken<?> typeToken);

@Nullable
protected abstract C createContext(@Nonnull TypeToken<?> typeToken);

@Nullable
protected abstract T read(@Nullable C context, @Nonnull TypeAdapter<? extends T> delegateAdapter, @Nonnull JsonReader in)
throws IOException;

@Override
@Nullable
public final <U> TypeAdapter<U> create(final Gson gson, final TypeToken<U> typeToken) {
if ( !supports(typeToken) ) {
return null;
}
@SuppressWarnings("unchecked")
final TypeAdapter<T> delegateAdapter = (TypeAdapter<T>) gson.getDelegateAdapter(this, typeToken);
@Nullable
final C context = createContext(typeToken);
final TypeAdapter<T> quirkyAdapter = new TypeAdapter<T>() {
@Override
public void write(final JsonWriter out, final T value)
throws IOException {
delegateAdapter.write(out, value);
}

@Override
public T read(final JsonReader in)
throws IOException {
return AbstractQuirkyTypeAdapterFactory.this.read(context, delegateAdapter, in);
}
}
.nullSafe();
@SuppressWarnings("unchecked")
final TypeAdapter<U> typeAdapter = (TypeAdapter<U>) quirkyAdapter;
return typeAdapter;
}

}
public final class QuirkyBooleanTypeAdapterFactory
extends AbstractQuirkyTypeAdapterFactory<Boolean, Void> {

private static final TypeAdapterFactory instance = new QuirkyBooleanTypeAdapterFactory();

private QuirkyBooleanTypeAdapterFactory() {
}

public static TypeAdapterFactory getInstance() {
return instance;
}

@Override
protected boolean supports(@Nonnull final TypeToken<?> typeToken) {
final Class<?> rawType = typeToken.getRawType();
return rawType == boolean.class
|| rawType == Boolean.class;
}

@Nullable
@Override
protected Void createContext(@Nonnull final TypeToken<?> typeToken) {
return null;
}

@Override
@Nullable
@SuppressWarnings("NestedSwitchStatement")
protected Boolean read(@Nullable final Void context, @Nonnull final TypeAdapter<? extends Boolean> delegateAdapter, @Nonnull final JsonReader in)
throws IOException {
final JsonToken token = in.peek();
switch ( token ) {
case BOOLEAN:
return delegateAdapter.read(in);
case NUMBER:
final int i = in.nextInt();
switch ( i ) {
case 0:
return false;
case 1:
return true;
default:
throw new JsonSyntaxException("Unhandled integer: " + i);
}
case STRING:
final String s = in.nextString();
switch ( s ) {
case "0":
case "false":
case "null":
return false;
case "1":
case "true":
return true;
default:
throw new JsonSyntaxException("Unhandled string: " + s);
}
case NULL:
return null; // TODO or false?
case BEGIN_ARRAY:
case END_ARRAY:
case BEGIN_OBJECT:
case END_OBJECT:
case NAME:
case END_DOCUMENT:
throw new JsonSyntaxException("Unhandled token: " + token);
default:
throw new AssertionError(token);
}
}

}
public final class QuirkyNumberTypeAdapterFactory
extends AbstractQuirkyTypeAdapterFactory<Number, Number> {

private static final TypeAdapterFactory instance = new QuirkyNumberTypeAdapterFactory();

private static final Function<Class<?>, Number> getKnownZero = new ImmutableMap.Builder<Class<?>, Number>()
.put(byte.class, (byte) 0)
.put(Byte.class, (byte) 0)
.put(short.class, (short) 0)
.put(Short.class, (short) 0)
.put(int.class, 0)
.put(Integer.class, 0)
.put(long.class, 0L)
.put(Long.class, 0L)
.put(float.class, 0F)
.put(Float.class, 0F)
.put(double.class, 0D)
.put(Double.class, 0D)
.put(BigInteger.class, BigInteger.ZERO)
.put(BigDecimal.class, BigDecimal.ZERO)
.build()
::get;

private QuirkyNumberTypeAdapterFactory() {
}

public static TypeAdapterFactory getInstance() {
return instance;
}

@Override
@SuppressWarnings("OverlyComplexBooleanExpression")
protected boolean supports(@Nonnull final TypeToken<?> typeToken) {
final Class<?> rawType = typeToken.getRawType();
return Number.class.isAssignableFrom(rawType)
|| rawType == byte.class
|| rawType == short.class
|| rawType == int.class
|| rawType == long.class
|| rawType == float.class
|| rawType == double.class;
}

@Nullable
@Override
protected Number createContext(@Nonnull final TypeToken<?> typeToken) {
return getKnownZero.apply(typeToken.getRawType());
}

@Override
@Nullable
@SuppressWarnings("NestedSwitchStatement")
protected Number read(@Nullable final Number knownZero, @Nonnull final TypeAdapter<? extends Number> delegateAdapter, @Nonnull final JsonReader in)
throws IOException {
final JsonToken token = in.peek();
switch ( token ) {
case NUMBER:
return delegateAdapter.read(in);
case STRING:
final String s = in.nextString();
switch ( s ) {
case "null":
case "false":
if ( knownZero == null ) {
return delegateAdapter.read(new JsonReader(new StringReader("0"))); // TODO optimize "constant" reading or cache previously unknown zero
}
return knownZero;
default:
return delegateAdapter.fromJsonTree(new JsonPrimitive(s)); // TODO optimize bypassing the intermediate JSON element
}
case BOOLEAN:
final boolean b = in.nextBoolean();
if ( !b ) {
if ( knownZero == null ) {
return delegateAdapter.read(new JsonReader(new StringReader("0"))); // TODO optimize "constant" reading or cache previously unknown zero
}
return knownZero;
}
throw new JsonSyntaxException("Unhandled boolean: " + b);
case NULL:
return null; // TODO or zero?
case BEGIN_ARRAY:
case END_ARRAY:
case BEGIN_OBJECT:
case END_OBJECT:
case NAME:
case END_DOCUMENT:
throw new JsonSyntaxException("Unhandled token: " + token);
default:
throw new AssertionError(token);
}
}

}
public final class QuirkyCollectionTypeAdapterFactory
extends AbstractQuirkyTypeAdapterFactory<Collection<?>, Void> {

private static final TypeAdapterFactory instance = new QuirkyCollectionTypeAdapterFactory();

private QuirkyCollectionTypeAdapterFactory() {
}

public static TypeAdapterFactory getInstance() {
return instance;
}

@Override
protected boolean supports(@Nonnull final TypeToken<?> typeToken) {
return Collection.class.isAssignableFrom(typeToken.getRawType());
}

@Nullable
@Override
protected Void createContext(@Nonnull final TypeToken<?> typeToken) {
return null;
}

@Override
@Nullable
protected Collection<?> read(@Nullable final Void context, @Nonnull final TypeAdapter<? extends Collection<?>> delegateAdapter,
@Nonnull final JsonReader in)
throws IOException {
final JsonToken token = in.peek();
switch ( token ) {
case BEGIN_ARRAY:
return delegateAdapter.read(in);
case BOOLEAN:
final boolean b = in.nextBoolean();
if ( !b ) {
return delegateAdapter.read(new JsonReader(new StringReader("[]"))); // TODO optimize "constant" reading (caching is not possible: collections are supposed be new and mutable)
}
throw new JsonSyntaxException("Unhandled boolean: " + b);
case NULL:
return null; // TODO or empty collection?
case END_ARRAY:
case BEGIN_OBJECT:
case END_OBJECT:
case NAME:
case STRING:
case NUMBER:
case END_DOCUMENT:
throw new JsonSyntaxException("Unhandled token: " + token);
default:
throw new AssertionError(token);
}
}

}

The above approach implements the Template Method design pattern for all three individual cases: booleans, numbers, and arrays (JSON arrays, but Java collections, I didn't include the Java arrays adapter for brevity).

The shared logic behind them all is as follows:

  • The type adapter factory checks whether it can handle the given type.
  • If it can, then it asks Gson for the delegate type adapter to deal then with.
  • Creates a generic type adapter that simply delegates the write operation to the original type adapter, but the read operation is specialized in each subclass where it is accessed from.
  • Each read operation implements simple JSON token peeking to decide how to proceed further based on the quirks you described in your question.

Having the following JSON:

{
"booleans": [
true,
false,
0,
1,
"0",
"1",
"true",
"false",
null,
"null"
],
"numbers": [
42,
"42",
null,
"null",
false,
"false"
],
"arrays": [
[
"foo",
"bar"
],
[],
false,
null
]
}

the following test passes:

@AllArgsConstructor(access = AccessLevel.PRIVATE)
@ToString
final class Data {

@SerializedName("booleans")
final List<Boolean> booleans;

@SerializedName("numbers")
final List<Number> numbers;

@SerializedName("arrays")
final List<List<String>> arrays;

}
public final class QuirksTest {

private static final Gson gson = new GsonBuilder()
.disableHtmlEscaping()
.disableInnerClassSerialization()
.registerTypeAdapterFactory(QuirkyBooleanTypeAdapterFactory.getInstance())
.registerTypeAdapterFactory(QuirkyNumberTypeAdapterFactory.getInstance())
.registerTypeAdapterFactory(QuirkyCollectionTypeAdapterFactory.getInstance())
.create();

@Test
@SuppressWarnings("ReturnOfNull")
public void test()
throws IOException {
try ( final JsonReader jsonReader = open("quirks.json") ) {
final Data data = gson.fromJson(jsonReader, Data.class);
Assertions.assertIterableEquals(
Arrays.asList(true, false, false, true, false, true, true, false, null, false),
data.booleans
);
Assertions.assertIterableEquals(
Arrays.asList(42, 42, null, 0, 0, 0),
data.numbers
.stream()
.map(n -> n != null ? n.intValue() : null)
.collect(Collectors.toList())
);
Assertions.assertIterableEquals(
Arrays.asList(
Arrays.asList("foo", "bar"),
Collections.emptyList(),
Collections.emptyList(),
null
),
data.arrays
);
}
}

}


Related Topics



Leave a reply



Submit