Skip to content

Instantly share code, notes, and snippets.

@turboBasic
Last active April 9, 2020 13:23
Show Gist options
  • Select an option

  • Save turboBasic/c48e4f5adc4925a0f454b9f6acfc943d to your computer and use it in GitHub Desktop.

Select an option

Save turboBasic/c48e4f5adc4925a0f454b9f6acfc943d to your computer and use it in GitHub Desktop.
Represent Groovy class as Map #groovy
interface Mappable {
Map asMap()
}
abstract class AbstractMappableImpl implements Mappable {
Set options
Set getOptions() {
options
}
void setOptions(Collection options) {
this.options = options as Set
}
void setOptions(def options) {
setOptions([options].flatten())
}
@NonCPS
final Map asMap() {
fieldsProvider()
.collectEntries {
[(it.name): fieldTransformer(it)]
}
}
@NonCPS
List fieldsProvider() {
ownFieldsProvider()
}
abstract def fieldTransformer(def field)
@NonCPS
final List ownFieldsProvider() {
privateFields().toList() +
allProperties().toList()
}
@NonCPS
final protected List privateFields() {
this.class
.declaredFields
.findAll {
!it.synthetic &&
it.modifiers != java.lang.reflect.Modifier.PUBLIC
}
}
@NonCPS
final protected List allProperties() {
this.metaClass
.properties
.findAll { 'class' != it.name }
}
}
class MappableImpl extends AbstractMappableImpl {
enum Options {
OWN_PROPERTIES,
INHERITED_PROPERTIES,
RECURSE_INTO_CLASSES,
PRIVATE_FIELDS
}
Set options = [
Options.OWN_PROPERTIES,
Options.INHERITED_PROPERTIES,
]
@NonCPS
@Override
Set<Options> getOptions() {
options.intersect(Options.values().toList())
}
void setOptions(Collection options) {
Set result = [] as Set
options.each {
try {
result << Options.valueOf( "${it}".trim().toUpperCase() )
}
catch(e) {}
}
this.options = result
}
@NonCPS
@Override
List fieldsProvider() {
super.fieldsProvider()
.findAll {
if (!options.contains(Options.INHERITED_PROPERTIES))
return it.type == this.class
if (!options.contains(Options.OWN_PROPERTIES))
return it.type != this.class
if (!options.contains(Options.PRIVATE_FIELDS)) {
return it.type != this.class
}
}
}
@NonCPS
@Override
def fieldTransformer(def field) {
def obj
if (field instanceof java.lang.reflect.Field) {
obj = field.getType()
} else {
obj = field
}
if (Options.RECURSE_INTO_CLASSES in options) {
if (Mappable.isAssignableFrom(obj))
delegate."${obj.name}" ?. asMap()
else
delegate."${obj.name}"
} else {
this."${field.name}"
}
}
@NonCPS
Mappable withOptions(def options) {
if (options instanceof Collection)
setOptions(this.options + options)
else
setOptions(this.options + [options])
return this
}
}
class Y extends MappableImpl {
String yProp1 = '111'
private String yField2 = 'private in Y'
}
class Z extends Y {
Map zProp1 = [
a: 12,
b: 'xxx'
]
private String zField = 'private in Z'
}
String prettify(def obj) {
groovy.json.JsonOutput.prettyPrint(
groovy.json.JsonOutput.toJson(obj)
)
}
@NonCPS
def getData() {
Map y = new Y().asMap()
Map z = new Z().withOptions(['INHERITED_PROPERTIES', 'PRIVATE_FIELDS','RECURSE_INTO_CLASSES']).asMap()
return [ y, z ]
}
node() {
println 'y: ' + prettify(getData()[0])
println 'z: ' + prettify(getData()[1])
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment