I would like to ask you for help. I have a Device object
public class Device {
public String name;
public String deviceId;
#JsonSerialize(using = CustomResourceSerializer.class)
public Map<String, Map<String, Object>> customResources;
}
My goal is to "extract" this map directly to Device Object. Firstly I used #JsonAnyGetter which worked well and Map was nested under field String of first map directly under Device object.
But I need more complex logic and I have two problems which I don't know how to solve.
Key of first map is for example "configuration/inputOne". With #JsonAnyGetter the example output is { "configuration/inputOne": { "rate":23 } }
What I need is nested structure based on delimiter, so
{ "configuration": { "inputOne": { "rate":23 } } }
This I was almost able to do easily with custom JsonSerializer
jsonGenerator.writeStartObject();
foreach(splited key)
jsonGenerator.writeObjectFieldStart(resourceUriItem);
foreach(value)
jsonGenerator.writeObjectField(k, v);
foreach(splitted key)
jsonGenerator.writeEndObject();
jsonGenerator.writeEndObject();
But final object looks like
{ "customResource": {"configuration": { "inputOne": { "rate":23 } } } }
CustomResource field is from Device object and I don't know how to get rid of it. As with JsonAnyGetter. That's the first problem.
As you see, I am splitting the key of the map to have more nested strucutre, so from the "configuration/inputOne" to { configuration { inputOne { .. } }. But the map customResources can have of course multiple items, so for example:
"configuration/inputOne"
"configuration/inputTwo"
"configuration"
Now you probably see where is the problem. As I am iterating over keys and I am creating nested structure, I will override it. So for example, firstly I will create object configuration, then inputOne and fill it with fields. Closing objects. Then second item in map, creating configuration object and inputTwo object. But with creation of configuration, I will delete the one previously created with inputOne.
Do you have any proposal how to solve this? Thanks.
You can turn your map into a type of a tree by splitting on the / and creating a parent child relationship on the split items.
Using the following class as a tree element / node.
class TreeElement {
private String key;
private Object value;
private List<TreeElement> children;
public TreeElement(String key) {
this.key = key;
}
// getters and setters here
public void addChild(TreeElement child) {
if (this.children == null) {
this.children = new ArrayList<TreeElement>();
}
this.children.add(child);
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((key == null) ? 0 : key.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TreeElement other = (TreeElement) obj;
if (key == null) {
if (other.key != null)
return false;
} else if (!key.equalsIgnoreCase(other.key))
return false;
return true;
}
#Override
public String toString() {
return "TreeElement [key=" + key + ", value=" + value + ", children=" + children + "]";
}
}
And the following test code.
public static void main(String[] args) {
try {
// create the config1, config2, etc.. here
Device device1 = new Device();
device1.customResources = new HashMap<String, Map<String, Object>>();
device1.customResources.put("configuration/inputOne", config1);
device1.customResources.put("configuration/inputTwo", config2);
device1.customResources.put("configuration", config3);
device1.customResources.put("configuration", duplicateConfig3);
device1.customResources.put("otherConfig", otherConfig);
device1.customResources.put("thirdConfig1", thirdConfig1);
device1.customResources.put("thirdConfig1/inputOne", thirdConfig2);
device1.customResources.put("thirdConfig1/inputOne", duplicateThirdConfig2);
List<TreeElement> elements = new ArrayList<TreeElement>();
for (Map.Entry<String, Map<String, Object>> entry : device1.customResources.entrySet()) {
TreeElement element = generateElement(null, entry.getKey(), entry.getValue());
elements.add(element);
}
List<TreeElement> joinedElements = joinElements(elements);
for (TreeElement e : joinedElements) {
System.out.println(e.getKey() + " - " + e.getValue());
if (e.getChildren() != null) {
for (TreeElement c : e.getChildren()) {
System.out.println("\t" + c.getKey() + " - " + c.getValue());
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
This method generates a TreeElement from a Map> variable.
private static TreeElement generateElement(TreeElement parent, String item, Map<String, Object> value) {
try {
List<String> tokens = new ArrayList<String>(Arrays.asList(item.split("/")));
TreeElement child = new TreeElement(tokens.get(0));
boolean parentWasNull = false;
if (parent == null) {
parent = child;
parentWasNull = true;
}
if (tokens.size() > 1) {
if (parentWasNull == false) {
parent.addChild(child);
}
tokens.remove(0);
generateElement(child, StringUtils.join(tokens, "/"), value);
} else {
child.setValue(value);
if (parentWasNull == false) {
parent.addChild(child);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return parent;
}
This method joins common TreeElement objects into one parent and multiple children.
private static List<TreeElement> joinElements(List<TreeElement> elements) {
List<TreeElement> joinedElements = new ArrayList<TreeElement>();
for (TreeElement element : elements) {
if (joinedElements.contains(element) == true) {
// joined elment does not have children
if (joinedElements.get(joinedElements.indexOf(element)).getChildren() == null) {
joinedElements.get(joinedElements.indexOf(element)).setChildren(element.getChildren());
} else {
//joined element has children and the current element also has children
if (element.getChildren() != null) {
joinedElements.get(joinedElements.indexOf(element)).getChildren().addAll(element.getChildren());
}
}
/*
* set the value of joined element to the value of the current element; will overwrite
* any existing value if duplicates exist
*/
if (element.getValue() != null) {
joinedElements.get(joinedElements.indexOf(element)).setValue(element.getValue());
}
} else {
joinedElements.add(element);
}
}
return joinedElements;
}
I'm not sure how efficient this code is, but you get the below output which you can traverse in your custom serializer to print to JSON.
thirdConfig1 - {rate=30}
inputOne - {rate=3020}
configuration - {rate=1200}
inputOne - {rate=23}
inputTwo - {rate=50}
otherConfig - {rate=10}
Related
I would like to know how to sort Apache Commons MultiValuedMap by Key. The below is the key class used.
public class VssKey implements Comparable<VssKey> {
private String funCode;
private String varntCode;
private String itemNb;
public VssKey(SummaryDataOracle summaryDataOracle) {
this.funCode = summaryDataOracle.getFuncCode();
this.varntCode = summaryDataOracle.getVariantCd();
this.itemNb = summaryDataOracle.getItemNB();
}
public String getFunCode() {
return funCode;
}
public void setFunCode(String funCode) {
this.funCode = funCode;
}
public String getVarntCode() {
return varntCode;
}
public void setVarntCode(String varntCode) {
this.varntCode = varntCode;
}
public String getItemNb() {
return itemNb;
}
public void setItemNb(String itemNb) {
this.itemNb = itemNb;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((funCode == null) ? 0 : funCode.hashCode());
result = prime * result + ((itemNb == null) ? 0 : itemNb.hashCode());
result = prime * result + ((varntCode == null) ? 0 : varntCode.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
VssKey other = (VssKey)obj;
if (funCode == null) {
if (other.funCode != null)
return false;
} else if (!funCode.equals(other.funCode))
return false;
if (itemNb == null) {
if (other.itemNb != null)
return false;
} else if (!itemNb.equals(other.itemNb))
return false;
if (varntCode == null) {
if (other.varntCode != null)
return false;
} else if (!varntCode.equals(other.varntCode))
return false;
return true;
}
#Override
public String toString() {
return String.format("VssKey [funCode=%s, varntCode=%s, itemNb=%s]", funCode, varntCode, itemNb);
}
#Override
public int compareTo(VssKey o) {
int k1 = Integer.parseInt(this.varntCode);
int k2 = Integer.parseInt(o.getVarntCode());
return k2 - k1;
}
}
The below map is constructed by iterating SummerDataOracle values. The values are pushed into the map by VssKey object as shown below.
MultiValuedMap<VssKey, String> partNumberVarientMap = new ArrayListValuedHashMap<>();
for (SummaryDataOracle summaryDataOracle : summeryDataOracleList) {
VssKey key = new VssKey(summaryDataOracle);
String varntText = null;
if (!StringUtils.isEmpty(summaryDataOracle.getVariantSmText())) {
varntText = summaryDataOracle.getVariantSmText().trim();
}
partNumberVarientMap.put(key, varntText);
}
I need to achieve the order in the Map.
Thanks
HashMap/MultivaluedHashMap cannot be sorted directly.
Better, to get its key and sort them and parse map in sorted order.
Map<String, List<String>> map = new MultivaluedHashMap<>();
map.put("b", new ArrayList<>());
map.put("a", new ArrayList<>());
List<String> keylist = new ArrayList<>(map.keySet());
Collections.sort(keylist);
for(String key : keylist) {
System.out.println(key + " : " + map.get(key));
}
By design, you can't sort a HashMap. If you need to keep a specific order in your map, it is recommended to use a Map implementation like TreeMap.
What you can do if you want to iterate over a HashMap in a specific order, is getting the keys and sort them. Then you can iterate over the keys and lookup your values accordingly:
HashMap<String, List<String>> map = new HashMap<>();
for(String key : new TreeSet<String>(map.keySet())){
map.get(key);
}
The following codes are aimed to export tree data structure into Map<String, String> so that can be easier to manipulate later. But the funny thing is toString() method works flawlessly but toMap() method got one missing parent A, child B. Anyone has any idea?
public static void main(String[] args) {
MutableTree<String> tree = new MappedTreeStructure<String>();
tree.add("A", "B");
tree.add("A", "C");
tree.add("C", "D");
tree.add("E", "F");
System.out.println(tree);
Map<String, String> myMap = tree.toMap();
if (myMap != null) {
for (Map.Entry<String, String> entry : myMap.entrySet()) {
System.out.println("parent: " + entry.getKey() + ", child: "
+ entry.getValue());
}
}
}
private final Map<N, N> nodeParent = new HashMap<N, N>();
private final LinkedHashSet<N> nodeList = new LinkedHashSet<N>();
#Override
public boolean add(N parent, N node) {
boolean added = nodeList.add(node);
nodeList.add(parent);
if (added) {
nodeParent.put(node, parent);
}
return added;
}
#Override
public boolean remove(N node, boolean cascade) {
if (!nodeList.contains(node)) {
return false;
}
if (cascade) {
for (N child : getChildren(node)) {
remove(child, true);
}
} else {
for (N child : getChildren(node)) {
nodeParent.remove(child);
}
}
nodeList.remove(node);
return true;
}
#Override
public List<N> getRoots() {
return getChildren(null);
}
#Override
public N getParent(N node) {
return nodeParent.get(node);
}
#Override
public List<N> getChildren(N node) {
List<N> children = new LinkedList<N>();
for (N n : nodeList) {
N parent = nodeParent.get(n);
if (node == null && parent == null) {
children.add(n);
} else if (node != null && parent != null && parent.equals(node)) {
children.add(n);
}
}
return children;
}
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
dumpNodeStructure(builder, null, "- ");
return builder.toString();
}
#Override
public Map<String, String> toMap() {
Map<String, String> map = new HashMap<String, String>();
dumpNodeToMap(map, null);
return map;
}
private void dumpNodeToMap(Map<String, String> map, N node) {
if (node != null) {
map.put((String) getParent(node), node.toString());
}
for (N child : getChildren(node)) {
dumpNodeToMap(map, child);
}
}
private void dumpNodeStructure(StringBuilder builder, N node, String prefix) {
if (node != null) {
builder.append(prefix);
builder.append(node.toString());
builder.append('\n');
prefix = " " + prefix;
}
for (N child : getChildren(node)) {
dumpNodeStructure(builder, child, prefix);
}
}
The output are following on console:
- A
- B
- C
- D
- E
- F
parent: null, child: E
parent: A, child: C
parent: C, child: D
parent: E, child: F
For references, these are the two interface classes being used:
public interface MutableTree <N extends Serializable> extends Tree<N> {
public boolean add (N parent, N node);
public boolean remove (N node, boolean cascade);
Map<String, String> toMap();
}
and
public interface Tree <N extends Serializable> extends Serializable {
public List<N> getRoots ();
public N getParent (N node);
public List<N> getChildren (N node);
}
Your toMap method returns a a Map<String, String> whose key is the parent element name and whose value is a single child element. This means that when the key is "A" only one child element can be stored, and this is being set to the last child element which is found, in this case "C", overwriting the entry for "A" which was pointing to "B".
Instead your toMap method needs to return a Map<String, List<String>> which maps from each parent node, such as "A", to a List of child elements, such as "B" and "C". Obviously it's fine if the List contains only one child element, but it must be a list in case there is more than one child.
The usual pattern for creating a List of items rather than a single item looks like this:
String parentNode = getParent(node).toString();
List<String> childElements = null;
if(map.contains(parentNode) {
// List of child elements already exists, so get it from the Map.
childElements = map.get(parentNode);
} else {
// List of child elements does not yet exist, so create a new List
// and add it to the Map.
childElements = new ArrayList<>();
map.put(parentNode, childElements);
}
childElements.add(node.toString());
I have a number of classes which can include one or more properties of the type TranslatableText. Also, some classes may have properties which themselves include such properties such as List<TranslatableText> or Map<String, TranslatableText>.
How would you go about scanning these classes in an efficient way, also picking up instances of TranslatableText in generic collections?
class Project{
String id;
TranslatableText name;
List<Action> actions;
}
class Action {
String id;
TranslatableText name;
TranslatableText description;
}
// getter & setters omitted
You can use a loop like this
// for super classes, use recursion.
for(Field f : obj.getClass().getDeclaredFields()) {
Class type = f.getType();
if (type == String.class || type == TranslatableText.class) {
Object value = f.get(object);
if (value != null)
map.put(f.getName(), value.toString());
}
Thanks to Peter Lawrey for the initial idea. This is what worked (so far) for me. I had to avoid circular recursion which is why I added the visited list. Arrays, Collections and Maps are scanned which is good enough for me at the moment.
/**
* Examine class members for TranslatableTexts. Traverse down into
* properties including Collections and Maps but ignoring java.lang classes
*
* #param obj
* #return
*/
public static Collection<? extends TranslatableText> getTranslatables(
Object obj, List<Object> visited)
{
List<TranslatableText> result = new ArrayList<TranslatableText>();
if (obj instanceof TranslatableText)
{
result.add((TranslatableText) obj);
return result;
}
if(visited.contains(obj))
return result;
visited.add(obj);
for (Field f : obj.getClass().getDeclaredFields())
{
f.setAccessible(true);
Class type = f.getType();
if (type.isPrimitive() == false
&& (type.getPackage() == null || type.getPackage()
.getName().startsWith("java.lang") == false))
{
try
{
Object value = f.get(obj);
if (value != null)
{
if (type.isArray())
{
Class arraytype = type.getComponentType();
if (arraytype == TranslatableText.class)
{
TranslatableText[] tt = (TranslatableText[]) value;
if (tt != null)
{
for (TranslatableText t : tt)
{
result.add(t);
}
}
}
}
else if (type == TranslatableText.class)
{
TranslatableText tt = (TranslatableText) value;
if (tt != null)
result.add(tt);
}
else if (value instanceof Collection)
{
for (Object o : (Collection<?>) value)
{
result.addAll(getTranslatables(o, visited));
}
}
else if (value instanceof Map)
{
for (Object o : ((Map) value).values())
{
result.addAll(getTranslatables(o, visited));
}
}
else
{
result.addAll(getTranslatables(value, visited));
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
return result;
}
I have an ArrayList filled POJOs and I want to remove all POJOs, which have a duplicate variable. This is the POJO:
public static class UrlStore {
public String url;
public String data;
public UrlStore(String url) {
this.url = url;
}
public void setData(String data) {
this.data = data;
}
}
My way to remove duplicate "url"-variables in the ArrayList<UrlStore> is to iterate through the list and to remove those duplicates. It was said to me that I could simply use a Set to do this, but I can't figure out how to use it with an ArrayList containing POJOs. Or do you have even a better way?
Thanks for any suggestions!
You can override the equals() and hashCode() methods in your POJO and pass the List<UrlStore> to the Set.
List<UrlStore> listOfUrlStore = ......
Set<UrlStore> foo = new HashSet<UrlStore>(listOfUrlStore);
I have used a simple HashSet here , the correct implementation of Set depends on your requirement. You can even convert the Set back to the List .
listOfUrlStore.clear();
listOfUrlStore.addAll(foo);
package test.urlstore;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class DuplicateDemo{
public static void main(String[] args) throws Exception {
List<UrlStore> urlStores = new ArrayList<UrlStore>();
UrlStore usg = new UrlStore("google");
UrlStore usy = new UrlStore("yahoo");
UrlStore usb = new UrlStore("bing");
UrlStore usa = new UrlStore("ask");
UrlStore usd = new UrlStore("duckduckgo");
usg.setData("mail");
urlStores.add(usg);
usg = new UrlStore("google");
usg.setData("search");
urlStores.add(usg);
usg = new UrlStore("google");
usg.setData("doc");
urlStores.add(usg);
usg = new UrlStore("google");
usg.setData("search");
urlStores.add(usg);
usg = new UrlStore("google");
usy.setData("search");
urlStores.add(usy);
usy.setData("search");
urlStores.add(usy);
usb.setData("search");
urlStores.add(usb);
usb.setData("search");
urlStores.add(usb);
usa.setData("search");
urlStores.add(usa);
usd.setData("search");
urlStores.add(usd);
System.out.println("before removing duplicates");
// before removing duplicates
for (Iterator iterator = urlStores.iterator(); iterator.hasNext();) {
UrlStore urlStore = (UrlStore) iterator.next();
System.out.println(urlStore.toString());
}
System.out.println("\n\nafter removing duplicates");
//removing duplicates
Set<UrlStore> uniqueUrlStores = new HashSet<UrlStore>(urlStores);
//After removing duplicates
for (Iterator iterator = uniqueUrlStores.iterator(); iterator.hasNext();) {
UrlStore urlStore = (UrlStore) iterator.next();
System.out.println(urlStore.toString());
}
}
static class UrlStore {
public String url;
public String data;
public UrlStore(String url) {
this.url = url;
}
public void setData(String data) {
this.data = data;
}
#Override
public String toString() {
return "UrlStore [url=" + url + ", data=" + data + "]";
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((data == null) ? 0 : data.hashCode());
result = prime * result + ((url == null) ? 0 : url.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
UrlStore other = (UrlStore) obj;
if (data == null) {
if (other.data != null)
return false;
} else if (!data.equals(other.data))
return false;
if (url == null) {
if (other.url != null)
return false;
} else if (!url.equals(other.url))
return false;
return true;
}
}
}
Override hashCode() and equals() in your POJO and then:
List<URLStore>() list = //Your list;
Set<URLStore> set =new HashSet<URLStore>(list);
Don't forget to override the equals method of your POJO.
One this is done, you could use contains method of List to check if your object is in the list before add it.
For the Set, you don't have to use it with the list, it replace the list. You can populate a Set from a List with addAll(Collection c)
I have a J2ME Application in which i need to bind my XML response in J2ME.Will you please help me in this case?How to bind XML Data Binding in J2ME?
JiBX seems to support J2ME. See the following related JIRA issue: [#JIBX-110] Having a J2ME compatible official jibx release.
Once downloaded, you'll have to ant-build the j2me jars using the j2me target (ant j2me from the build directory where build.xml is sitting). You can just build it with a standard javac, no need for a specialized compiler (see this discussion in the JiBX users list).
It seems that what you want is to unmarshall an XML file to a Java class. If so, I have shared a generic way at my blog. It uses two classes to implement it. The code of the first class is:
public class XMLTag {
// if you do not have enough memory, use lazy
// instantiation on these attributes
private Hashtable attributes = new Hashtable();
private Vector childs = new Vector();
public void setAttributeValue(String attribute, String value) {
if (attribute != null && value != null) {
attributes.put(attribute, value);
}
}
public String getAttributeValue (String attribute) {
return (String) attributes.get(attribute);
}
public void addChild (XMLTag child) {
childs.addElement(child);
}
public Enumeration getChilds () {
return childs.elements();
}
public XMLTag getChildAt (int index) {
return (XMLTag) childs.elementAt(index);
}
}
Below is the source code of the second class:
class XMLBinder extends org.xml.sax.helpers.DefaultHandler {
private Hashtable map = new Hashtable();
private Stack stack = new Stack();
private XMLTag rootElement;
private String attribute;
private StringBuffer value = new StringBuffer();
/**
* #param map with String keys and XMLTag values
*/
public XMLBinder(Hashtable map) {
Enumeration e = map.keys();
while (e.hasMoreElements()) {
Object key = e.nextElement();
Object tag = map.get(key);
if (validateMapping(key, tag)) {
this.map.put(key, tag);
} else {
throw new IllegalArgumentException("key " + key);
}
}
}
private boolean validateMapping (Object key, Object tag) {
return key instanceof String
&& tag instanceof Class
&& XMLTag.class.isAssignableFrom((Class) tag);
}
public XMLTag unmarshall (InputStream in) throws IOException {
try {
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse(in, this);
return rootElement;
} catch (Exception ex) {
throw new IOException("caused by " + ex);
}
}
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
Class tag = (Class) map.get(qName);
if (tag != null) {
try {
XMLTag newTag = (XMLTag) tag.newInstance();
addAttributesToXMLTag(attributes, newTag);
stack.push(newTag);
} catch (Exception e) {
throw new SAXException("caused by " + e);
}
} else {
attribute = qName;
}
}
private void addAttributesToXMLTag (Attributes attributes, XMLTag newTag) {
if (attributes != null) {
for (int i = attributes.getLength() - 1; i >= 0; i--) {
String attrName = attributes.getQName(i);
String attrValue = attributes.getValue(i);
newTag.setAttributeValue(attrName, attrValue);
}
}
}
public void characters(char[] ch, int start, int length) {
if (attribute != null) {
value.append(ch, start, length);
}
}
public void endElement(String uri, String localName, String qName)
throws SAXException {
if (stack.isEmpty()) {
throw new SAXException("no mapping for " + qName);
}
if (attribute != null && attribute.equals(qName)) {
XMLTag parent = (XMLTag) stack.peek();
parent.setAttributeValue(attribute, value.toString());
attribute = null;
value.setLength(0);
} else {
XMLTag child = (XMLTag) stack.pop();
if (stack.isEmpty() == false) {
XMLTag parent = (XMLTag) stack.peek();
parent.addChild(child);
} else {
rootElement = (XMLTag) child;
}
}
}
}
To prevent the use of Class.forName we use a map with tags and classes. The key is a String with the tag name and the value is a Class that extends XMLTag. For example, reading an RSS feed would use below classes:
class RSS extends XMLTag {
Channel channel;
public void addChild(XMLTag child) {
if (child instanceof Channel) {
channel = (Channel) child;
}
}
}
class Channel extends XMLTag {
public void addChild(XMLTag child) {
if (child instanceof Item) {
super.addChild(child);
}
}
}
class Item extends XMLTag {
}
And the following map:
Hashtable map = new Hashtable();
map.put("rss", RSS.class);
map.put("channel", Channel.class);
map.put("item", Item.class);
The binder can then be used:
XMLBinder binder = new XMLBinder(map);
rss = (RSS) binder.unmarshall(in);
Update after comments
For your xml sample you need to create the following classes:
class DataTable extends XMLTag {
XsSchema xsSchema;
DiffgrDiffgram diffgrDiffgram;
public void addChild(XMLTag child) {
if (child instanceof XsSchema) {
xsSchema = (XsSchema) child;
}
else if (child instanceof DiffgrDiffgram) {
diffgrDiffgram = (DiffgrDiffgram) child;
}
}
}
class XsSchema extends XMLTag {
}
class DiffgrDiffgram extends XMLTag {
}
and use the following map
Hashtable map = new Hashtable();
map.put("DataTable", DataTable.class);
map.put("xs:schema", XsSchema.class);
map.put("diffgr:diffgram", DiffgrDiffgram.class);