Last active
December 17, 2021 16:22
-
-
Save sam33rdhakal/02e9a0908e7592c31ebd to your computer and use it in GitHub Desktop.
Script for generating RealmObject Serializer. Uses JavaPoet to write file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
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
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.