Skip to content

Instantly share code, notes, and snippets.

@sam33rdhakal
Last active December 17, 2021 16:22
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sam33rdhakal/02e9a0908e7592c31ebd to your computer and use it in GitHub Desktop.
Save sam33rdhakal/02e9a0908e7592c31ebd to your computer and use it in GitHub Desktop.
Script for generating RealmObject Serializer. Uses JavaPoet to write file.
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.squareup.javapoet.*;
import javax.lang.model.element.Modifier;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
/**
* Class to generate the RealmObject's Serializer Class
* Uses JavaPoet library
*
* @author sdhakal on 2/29/16 (Fuzz).
*/
public class HowdysRealmSerializerGenerator {
/**
* @param modelPackage {@link String} package where model (RealmObject) are located
* @param pkgName {@link String} package name for output where Serializers are to be located
*/
public void start(String modelPackage, String pkgName) {
Class[] classes = null;
try {
classes = getClasses(modelPackage);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
for (Class klass : classes) {
generateJsonSerializer(modelPackage, pkgName, klass);
}
}
/**
* @param modelPackage {@link String} model package
* @param pkgName {@link String} package name for output
* @param klazz {@link Class} target RealmObject class
*/
private void generateJsonSerializer(String modelPackage, String pkgName, Class<?> klazz) {
//get class name
ClassName className = ClassName.bestGuess(klazz.getName());
String packageName = klazz.getPackage().toString().replace("package ", "");
String simpleClassName = klazz.getName().toLowerCase().replace(packageName, "").replace(".", "");
MethodSpec.Builder serializerMethodBuilder = MethodSpec.methodBuilder("serialize")
.addAnnotation(Override.class)
.returns(JsonElement.class)
.addParameter(className, simpleClassName)
.addParameter(Type.class, "typeOfSrc")
.addParameter(JsonSerializationContext.class, "context")
.addModifiers(Modifier.PUBLIC);
serializerMethodBuilder.addStatement("final $T jsonObject = new $T()", JsonObject.class, JsonObject.class);
Field[] fields = klazz.getDeclaredFields();
for (Field field : fields) {
String fieldName = field.getName().replace(packageName, "").replace(".", "");
if (ifFieldIsPrimitive(field)) {
serializerMethodBuilder.addStatement("jsonObject.addProperty($S, $L.get$L())", fieldName, simpleClassName.toLowerCase(), generateGetter(fieldName));
} else {
serializerMethodBuilder.addStatement("jsonObject.add($S, context.serialize($L.get$L()))", fieldName, simpleClassName.toLowerCase(), generateGetter(fieldName));
}
}
serializerMethodBuilder.addStatement("return jsonObject");
MethodSpec welcomeOverlords = serializerMethodBuilder.build();
ClassName jsonSerializer = ClassName.get(JsonSerializer.class);
TypeName interfaceType = ParameterizedTypeName.get(jsonSerializer, className);
TypeSpec.Builder builder = TypeSpec.classBuilder(klazz.getSimpleName() + "Serializer")
.addSuperinterface(interfaceType)
.addMethod(welcomeOverlords)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
JavaFile javaFile = JavaFile.builder(pkgName, builder.build())
.build();
try {
Path path = Paths.get("src/main/java/");
javaFile.writeTo(path);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* @param field {@link Field}
* @return {@link boolean} true if {@link Field} is primitive, else false
*/
private boolean ifFieldIsPrimitive(Field field) {
Type type = field.getType();
if (type == Integer.TYPE || type == Float.TYPE || type == Long.TYPE ||
type == Short.TYPE || type == Character.TYPE ||
type == Byte.TYPE || type == Boolean.TYPE || type == String.class) {
return true;
} else {
return false;
}
}
/**
* @param input {@link String} field name
* @return formatted {@link String} getter for input
*/
private String generateGetter(String input) {
return input.substring(0, 1).toUpperCase() + input.substring(1);
}
/**
* Get Model Files inside given package
*
* @param packageName {@link String} model package
* @return {@link List<Class>}
* @throws ClassNotFoundException
* @throws IOException
*/
private Class[] getClasses(String packageName)
throws ClassNotFoundException, IOException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
assert classLoader != null;
String path = packageName.replace('.', '/');
Enumeration<URL> resources = classLoader.getResources(path);
List<File> dirs = new ArrayList<File>();
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
dirs.add(new File(resource.getFile()));
}
ArrayList<Class> classes = new ArrayList<Class>();
for (File directory : dirs) {
classes.addAll(findClasses(directory, packageName));
}
return classes.toArray(new Class[classes.size()]);
}
/**
* Recursive method used to find all classes in a given directory and subdirs.
*
* @param directory The base directory
* @param packageName The package name for classes found inside the base directory
* @return The classes
* @throws ClassNotFoundException
*/
private List<Class> findClasses(File directory, String packageName) throws ClassNotFoundException {
List<Class> classes = new ArrayList<Class>();
if (!directory.exists()) {
return classes;
}
File[] files = directory.listFiles();
for (File file : files) {
if (file.isDirectory()) {
assert !file.getName().contains(".");
classes.addAll(findClasses(file, packageName + "." + file.getName()));
} else if (file.getName().endsWith(".class")) {
classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6)));
}
}
return classes;
}
}
@sam33rdhakal
Copy link
Author

To generate serializer classes import JavaPoet library and then use two line as below.

    HowdysRealmSerializerGenerator howdysRealmSerializerGenerator = new HowdysRealmSerializerGenerator();
    howdysRealmSerializerGenerator.start("model", "serialize");

@Alqueraf
Copy link

Hi @sam33rdhakal thanks for that awesome script!
However I am not able to use it, do you run it on the Android Studio project itself? I am missing some imports that android studio is not able to resolve (Modifier, Path and Paths).
Many thanks.

@TechNov
Copy link

TechNov commented Dec 17, 2021

After tow days of bug resolve, i found this SIMPLE solution.

YourRealmObject realmObj = realm.where(YourRealmObject.class).findFirst(); if(realmObj != null) { realmObj = realm.copyFromRealm(realmObj); //detach from Realm, copy values to fields String json = gson.toJson(realmObj); }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment