LibGDX Android Production Failing to Load from JSON - java
I have developed and released a game using LibGDX platform for Android. I'm using Json to save and load information:
To save an object (a rocket class):
Json json = new Json();
String rocketStr = json.toJson(rocket);
To load this object:
Rocket rocket = json.fromJson(Rocket.class, rocketStr);
After the release, I have added a new advertising provider (adMob) and released the update to the game. I have not made any changes to the classes which are being saved. And I have not changed any library versions. The only change was some new classes added and used in the project.
With this new update the game could no longer load the saved objects with Json - it would come up with an exception when trying to run json.fromJson(Rocket.class, rocketStr); Exceptions would differ but mainly there were two: 1) property not found or 2) unable to cast value to some property.
After some experimenting, I found out that in production Android (or LibGDX?) obscures all the class names and property names and when Json is writing a class the resulting string looks like this:
{A:97.50652,A2:{E:RIGHTTHRUSTER,F:true,a:Liberator Thrusters,b:2,d:false,f:true,g:{}},H:24.934832,I:10,J:true,K:30,M2:1587,N2:1647,O2:1527,Y:-7.3379517,a:{seed0:28965116732361103,seed1:-4728429348234121846},a0:-19.308016,b:Liberator,b0:17.0175,c:1,d:1,e:false,j0:{a:500},m:true,o:497.43192,p:1587,s:100,t:100,u2:{E:TOP,F:true,a:Liberator Nose,b:1,c:1,d:false,f:true,f0:[],g:{}},z2:{E:LEFTTHRUSTER,F:true,a:Liberator Thrusters,b:2,c:1,d:false,f:true,f0:[],g:{}}}
And after the update, the same object saved has some different field names:
{B2:{E:LEFTTHRUSTER,F:true,a:Liberator Thrusters,b:43,c:1,f:true,f0:[],g:{}},C:100,D2:{E:RIGHTTHRUSTER,F:true,a:Liberator Thrusters,b:43,f:true,g:{}},J:0.128269,K:-7.5,L:true,N:true,O2:1587,P2:1647,Q2:1527,R:-5,a0:-2.9551423,c:{seed0:-3537680883966184457,seed1:6879650071827728698},d:Liberator,e:17,f:1,l0:{a:500},o:true,q:595.54803,r:1587,u:100,v:100,w2:{E:TOP,F:true,a:Liberator Nose,b:42,c:1,f:true,f0:[],g:{}}}
For example, in first example one of the properties is called 'A2' and in the second example the same property is called 'D2'
Is my understanding correct that Android (or LibGDX?) can change the obfuscated class names for the same classes when I make some changes to the project?
And most importantly, what can I do to make sure that the class / property names stay the same to be able to save and load the same object with Json after any updates? Are there any alternatives / better methods to save / load information?
Related
How do you retrieve the AssetType from an Asset when using the xero API in a maven java application?
I have integrated the XERO-API on my java application and I need to display a list of Assets along with their AssetType. I have seen that when you make a Postman call to get all Assets, the JSON object items returned contain the "assetTypeId" attribute as well as in the API documentation the "assetTypeId" attribute is returned. However the Asset.class from the java sdk does not contain the "assetTypeId" property. Is there another way to get the AssetType from an Asset using the xero-api java sdk? I am using v3.5.2 of the jar.
that field should be serialized back based on the model definition. Can you post back what you are receiving from the SDK public class AssetType { #JsonProperty("assetTypeId") private UUID assetTypeId; #JsonProperty("assetTypeName") private String assetTypeName; ... etc Source https://github.com/XeroAPI/Xero-Java/blob/master/src/main/java/com/xero/models/assets/AssetType.java#L33 Let me know what is being returned and we try to see why thats not being serialized back.
AEM asset Is there any way to move a file by creating a folder in a workflow in java
I want to move few assets by creating a new folder using only the workflow in java.I dont want to create the folders manually and then move the assets as there are 10000s of assets that are to be moved to different folders.
If you are looking at creating folder using workflow - A folder in AEM is nothing but a node of jcr:primaryType either sling:Folder or sling:OrderedFolder. If you have com.day.cq.commons.jcr in your classpath, createPath method will help you create a node if it does not exist. You could also use addNode method followed by setProperty method from javax.jcr.Node api to create this folder of appropriate primary type. Moving assets to this newly created node(folder), can proceed after this. You could use the clone method from javax.jcr.WorkSpace which has an option to remove the existing node. There is another straight forward way to move assets. I would recommend you to use built-in com.adobe.granite.asset.api.AssetManager api to perform CRUD operations on DAM assets. session = resourceResolver.adaptTo(Session.class); String assetPath = "/content/dam/folderA/asset1.jpg"; String movePath = "/content/dam/folderB/asset1.jpg"; assetManager.moveAsset(assetPath, copyPath); session.save() session.logout() Further references for AssetManager API. HelpX Article API Details Moving large number of assets might cause the move operation to fail if there no appropriate indexes in place. Monitor logs for warning messages like The query read or traversed more than X nodes.. You might have to add oak based properties to the out-of-the-box /oak:index/ntBaseLucene index to fix this. More details here.
How can I add UnsignedProperties?
I'm trying to sign a XML document using XADES-BES and the smart card. I made some changes in the class SignerBES.java according to my needs and the signature creation is working well ! My question: How can I add UnsignedProperties to get something like this : <SignerRole> <ClaimedRoles> <ClaimedRole>EST</ClaimedRole> </ClaimedRoles> </SignerRole> </SignedSignatureProperties> <SignedDataObjectProperties> <DataObjectFormat ObjectReference="#sigId"> <Description>des</Description> <MimeType>text/xml</MimeType> <Encoding>base64</Encoding> </DataObjectFormat> <CommitmentTypeIndication> <CommitmentTypeId> <Identifier/> </CommitmentTypeId> <AllSignedDataObjects/> <CommitmentTypeQualifiers> <CommitmentTypeQualifier>commitment</CommitmentTypeQualifier> </CommitmentTypeQualifiers> </CommitmentTypeIndication> </SignedDataObjectProperties> </SignedProperties> <UnsignedProperties> <UnsignedSignatureProperties> <SignatureTimeStamp> <EncapsulatedTimeStamp>noTimStampToken</EncapsulatedTimeStamp> </SignatureTimeStamp> <CounterSignature/> <CompleteCertificateRefs/> <CompleteRevocationRefs/> <SigAndRefsTimeStamp/> <RefsOnlyTimeStamp/> <CertificatesValues/> <RevocationValues/> <ArchiveTimeStamp/> </UnsignedSignatureProperties> </UnsignedProperties> </QualifyingProperties> </ds:Object> this is a code snippet SignerBES.java: Collection<SignedSignatureProperty> fsssp = new ArrayList<SignedSignatureProperty>(2); Collection<UnsignedSignatureProperty> fsusp = new ArrayList<UnsignedSignatureProperty>(2); getFormatSpecificSignatureProperties(fsssp, fsusp, signingCertificateChain); // Gather all the signature and data objects properties. QualifyingProperties qualifProps = qualifPropsProcessor.getQualifyingProperties( signedDataObjects, fsssp, fsusp); // LOG System.out.println("fsusp"+fsusp.size()); I tried to add it at SignerBES.java and DefaultSignaturePropertiesProvider.java but I do not know how I can add it : public class DefaultSignaturePropertiesProvider implements SignaturePropertiesProvider { #Override public void provideProperties(SignaturePropertiesCollector signaturePropsCol) { signaturePropsCol.setSigningTime(new SigningTimeProperty()); signaturePropsCol.setSignerRole(new SignerRoleProperty("EST")); // UnsignedProperty // OtherUnsignedSignatureProperty otherUnsignedProp=null; // signaturePropsCol.addOtherSignatureProperty(otherUnsignedProp); }}
I don't think I understand completely what you're trying, since it seems you're messing around the lib source code. Anyway, check out this page on the project docs. Many of the unsigned qualifying properties are added automatically by xades4j when you use one of the signing profiles (e.g. if you use XAdesCSigningProfile, CompleteCertificateRefs/CompleteRevocationRefs are added). Other properties are part of advanced forms and can only be added during validation of an existing signature. Refer to this wiki page and [this javadocs page](http://luisgoncalves.github.io/xades4j/javadocs/1.4.0/reference/xades4j/verification/XadesVerifier.html#verify(org.w3c.dom.Element, xades4j.verification.SignatureSpecificVerificationOptions, xades4j.production.XadesSignatureFormatExtender, xades4j.verification.XAdESForm)) for additional info. Finally, some properties (e.g. CounterSignature) are not tied to any specific form, and can be added to any signature using a custom SignaturePropertiesProvider, registered on the signing profile that you are using.
What is the Tensorflow Java Api `toGraphDef` equivalent in Python?
I am using the Tensorflow Java Api to load an already created Tensorflow model into the JVM. I am using this as an example: tensorflow/examples/LabelImage.java Here is my simple scala code: import java.nio.file.{Files, Path, Paths} import org.tensorflow.{Graph, Session, Tensor} def readAllBytesOrExit(path: Path): Array[Byte] = Files.readAllBytes(path) val graphDef = readAllBytesOrExit(Paths.get("PATH_TO_A_SINGLE_FILE_DESCRIBING_TF_MODEL.pb")) val g = new Graph() g.importGraphDef(graphDef) val session = new Session(g) val result: Tensor = session.runner().feed("input", image).fetch("output").run().get(0)) How do I save my model to get both the Session and the Graph stored in the same file. as described in the "PATH_TO_A_SINGLE_FILE_DESCRIBING_TF_MODEL.pb" above. Described here it mentions: The serialized representation of the graph, often referred to as a GraphDef, can be generated by toGraphDef() and equivalents in other language APIs. What are the equivalents in other language APIs? I dont find it obvious Note: I already looked at the mnist_saved_model.py under tensorflow_serving but saving it through that procedure gives me a .pb file and a variables folder. When trying to load that .pb file I get: java.lang.IllegalArgumentException: Invalid GraphDef
Currently with the Java API of tensorflow, I only found how to save a graph as a graphDef (i.e. without its variables and meta-data). This can be done by just writing the Array[Byte] to a file: Files.write(Paths.get(modelDir, modelName), myGraph.toGraphDef) Here myGraph is a java object from the Graph class. I would suggest to save your model from the Python API, using the SavedModel api defined here. It will save your model in a folder with both the serialized graph in a .pb file and the variables in a folder. Note the tag_constants you use as you'll need it in your scala/java code to load the model with the variables. Then the graph and session with variables are easily loaded with the SavedModelBundle java class from the java api. It returns you a wrapper with both the graph and the session containing the variables values: val model = SavedModelBundle.load(modelDir, modelTag) If you already tried this, maybe you can share your code to see why it returned an invalid GraphDef. Another option is to freeze your graph, i.e. you turned your variable nodes into constant Nodes so everything is self-contained in the .pb file. Mores infos here for the freezing part
LibGDX: Cannot load a json file from assets folder
I have a json file with data for all the tiles in my game that I store in the assets folder. I try to access and parse it using TileList dataList = json.fromJson(TileList.class, Gdx.file.internal("map-elements/tiles/tiles.json")). This works fine for the desktop version but on the html version, after converting with gwt, I get these errors: GwtApplication: exception: Error reading file: map-elements/tiles/tiles.json Error reading file: map-elements/tiles/tiles.json Couldn't find Type for class 'net.vediogames.archipelo.world.tiles.TileList' TileList is a simple object that contains an array of TileData which can then be converted into Tile objects. I did it this way to make the json parsing easy.
The solution to the json error is simple. Instead of passing the FileHandle into the json parser, pass the string from the file like this: TileList dataList = json.fromJson(TileList.class, Gdx.file.internal("map-elements/tiles/tiles.json").readString()); In the end, all I needed to do to solve that issue is add .readString(). As for the Couldn't find Type for class 'net.vediogames.archipelo.world.tiles.TileList' error, I also found a solution but it is more complicated. JavaScript handles class references differently than Java. So I was not able to use TileList.class without first registering it so LibGDX can generate a Reflection. What I needed to do was add this line into my *.gwt.xml files: <extend-configuration-property name="gdx.reflect.include" value="net.vediogames.archipelo.world.tiles.TileList" /> If you want a full tutorial about how reflection works and how to include packages or exclude, please view the official LibGDX tutorial here.
Your solution was not working for me, I still got the same error. After some hours of testing I got it to work, using your suggestions and by using the ClassReflection instead of referencing the class itself. Your example: TileList dataList = json.fromJson(TileList.class, Gdx.file.internal("map-elements/tiles/tiles.json").readString()); looks in my working code like: TileList dataList = (TileList) json.fromJson(ClassReflection.forName(TileList.class.getName()), Gdx.file.internal("map-elements/tiles/tiles.json").readString()); This is quite a pain in the a.. but I'm glad it is finally working now.