I am having trouble deserializing objects that contain an enum. The object serializes without complaint, but I get an InvalidObjectException when I deserialize the object. The exception message says that there is "No enum constant com.mypackagname."
I have isolated and reproduced the problem by creating some test code based on the testSerialization() method in SerializationTest.java.
public class SerializationTest {
private static final String TEST_FILE_NAME = "serialization-test.bin";
public enum Gender { MALE, FEMALE }
public void testEnumSerialization() throws IOException, ClassNotFoundException {
Gender gender = Gender.MALE;
// Save the enum to a file.
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(TEST_FILE_NAME));
out.writeObject(gender);
out.close();
// Read back the enum.
ObjectInputStream in = new ObjectInputStream(new FileInputStream(TEST_FILE_NAME));
Gender gender2 = (Gender) in.readObject();
in.close();
}
}
I have discovered that if I add a string value to the enum initialization in the generated Objective C code the deserialization works fine. The resulting initialize method in Obj C looks like this:
+ (void)initialize {
if (self == [SerializationTest_Gender class]) {
JreEnum(SerializationTest_Gender, MALE) = new_SerializationTest_Gender_initWithNSString_withInt_(#"MALE", 0);
JreEnum(SerializationTest_Gender, FEMALE) = new_SerializationTest_Gender_initWithNSString_withInt_(#"FEMALE", 1);
J2OBJC_SET_INITIALIZED(SerializationTest_Gender)
}
}
Note that I added the #"MALE" and #"FEMALE", the default from the j2objc output is #"".
I have two questions. (1) Is this the correct way to enable a round trip serialization/deserialization of enums? (2) If so, is there a way to have j2objc automatically populate the string constants in the enum rather than coding them by hand?
Thanks for any help you can provide.
We probably broke this with a recent change eliminating redundant enum constant name strings. We had the name defined both in the enum's class initializer and in its metadata, plus we had an important request to stop making enum constants easily discovered in app binaries (apparently tech writers have been known to dump early access binaries and run strings on them to get scoops on any new features). Now the constant name is only in the metadata (no redundancy), and if an app builds with --strip-reflection, the enum has no metadata and the name becomes the enum class plus the constant's ordinal. However, serialization support was overlooked since Google apps use protocol buffers instead (faster and less version-sensitive).
Thanks for the excellent test case, which will make it easier to fix. Please file a bug if you want to be notified when this is fixed.
Related
I'm working on a school assignment for my compiler and interpreters course and our current task is to create a scanner and a set of tokens using JavaCC. I have a pretty solid understanding of how JavaCC works but my problem is finding resources online to help me out when I get stuck. I am working on creating a custom Token class, let's call it NewToken.Java. I know that the base Token class has an image variable and a kind variable but I want to implement my own variable "value". Furthermore I want to figure out how I can assign this value. I want the value variable to hold the literal value of what I scan, for example, my NewToken is being matched to the following
< IDENTIFIER:(< LETTER >)+ ( < LETTER > | < DIGIT >)* >
< #LETTER:["a" - "z"] >
< #DIGIT: ["0" - "9"] >
so something along the lines of Name123Name would get caught and when it does I want to store the string "Name123Name" into the 'value' variable of my NewToken object. I hope this makes sense, I am still new to JavaCC and may be calling things by there wrong name here.
public NewToken(){}
public NewToken(int kind){
this(kind,null);
}
public NewToken(int kind, String image){
this.kind=kind;
this.image=image;
this.value=image;
}
public String toString(){
return image;
}
public static Token newToken(int ofKind, String image){
switch(ofKind){
default : return new Token(ofKind, image);
}
}
public static Token newToken(int ofKind){
return newToken(ofKind, null);
}
}
Above is part of my code for the NewToken class, I have it extending Token and implementing java.io.serializable. I created by using the code generated for Token.java. I also have my variable declarations and my getValue() function which are not listed here to save space. I'm not looking for anyone to do my work for me I just need some guidance on how I would get this working, thank you in advance.
First off, I think the newToken routine should return objects of type NewToken rather than Token.
public static Token newToken(int ofKind, String image){
return new NewToken(ofKind, image);
}
public static Token newToken(int ofKind){
return new NewToken(ofKind, null);
}
(I don’t think you need that second method. But, I’m not completely sure, so I’ll leave it.)
It’s a bit unclear to me how you want value to differ from image, but I’m going to assume that you can compute the desired value for value from the image and the kind. And I’ll further assume that you have implemented this function as a static method.
private static String computeValue(int kind, String image) {...}
Delete the first two constructors and the remaining one should be:
private NewToken(int kind, String image){
this.kind = kind;
this.image = image;
this.value = computeValue( kind, image );
}
The answer that Professor Norvell is giving you is based on using a very old, obsolete version of JavaCC. The way he's suggesting you go about things is probably about the best way of doing it, if you were going to use the legacy JavaCC.
However, the most advanced version of JavaCC is JavaCC 21 and it handles this sort of use case straight out of the box in a very clean, elegant manner. See here for information on this specifically.
As you can see, you can put annotations in your grammar file that cause the various Token subclasses to be generated and used.
Also, JavaCC 21 has code injection that allows you to inject code directly into the any generated files, including the Token subclasses. That feature is not at all present in legacy JavaCC either. But using that, you could just inject your computeValue method right into the appropriate Token subclass.
INJECT NewToken :
{
private static String computeValue(int kind, String image) {...}
}
You put that in your grammar and the computeValue method just gets inserted into the generated NewToken.java file.
By the way, there is an article about JavaCC 21 that appeared recently on dzone.com.
imagine this:
DataTypeForConfigs config
with
String keys, but values of either String, Integer, or Boolean,
in Java, JSON can do that, but I'm making a format That goes along the lines of:
number "coolness" is 9001 means
int coolness = 9001;
It's method is: Read line, read each word, think what to make of it, set it to a Variable within it's reach
Also: what would happen if another thing had its own place to put config? a null would be read? WHY? constructor thinks a file has null on it? Rage face.
Say... should I make a class called SettingVal that when given a getValue() call it would say what it is?
SO:
config["Coolness"].getValue();
return's 9001
WAIT:
How on earth would I make the getValue() method? HOW? RETURN VALUE WONT LIKE THIS!! OH CRAP!
Solution:
Another Data type comes in and checks its 'gender' (String, Bool, Int) and then checks it's value of that 'gender' (strVal, boolVar, intVar)
Return values are a big problem when dealing with this. I need a stress free version, so maybe I can have a void returning method that runs another method based on what data type it is said to hold! Am I right?
I have a temporary solution, setVar works, getVar is get*Var, where * is Str, Bool or Int.
Sadly, I Haven't yet been able to properly read it from a file, the method I made to read from a file is not working. It makes a Map<String,SettingVar>, using a HashMap constructor and returns that map, but seems whenever I try to access a variable from it that variable is null. It is probably because of IOExceptions and FileNotFoundExceptions, FileNotFound? Why? It Shouldn't be running until called. Oh, and also NullPointerExceptions Please Help!
SUBQUESTION: what happens when you MapVariable.put({NAME HERE}, varToPutIn) many times in a for loop? what about MapVariable.put({NAME HERE},new ...)?
My code in links:
https://gist.github.com/anonymous/66c4d1c2d2718a4cc9b9
because I don't have enough reputation
P.S: OK! ive made the config reader work now, and SettingVar, and SettingContainer and im working on ConfigWriter which is good, now working on a prototype for a java command prompt like thing, and soon a WHOLE OS!! wait... java is an os. thats why java virtual machine... oh. Well, how can I close this question and turn the outcome into a revolutionary new thingy for kids who want to learn to code java *cough cough* especialy ones with higher learning ability than social ability... and like to hang around with mature people who dont bully them like all the kids in their school. (Wow, that was specific)
I would use a Plain Old Java Object which you can read from JSON.
class Config {
int coolness = 9001;
String hello = "world";
boolean cool = true;
}
This way you can have fields with a variety of types.
The type you're looking for is Map<String,Object>, but it is not type-safe and you'll have to do a bunch of casting:
Map<String,Object> config = new HashMap<>();
config.put("coolness",9001);
config.put("hello","world");
config.put("cool", true);
boolean cool = (Boolean) config.get("cool");
String hello = (String) config.get("world");
int coolness = (Integer) config.get("coolness");
Generally, I'd recommend creating a dedicated class for holding your configuration (each field = one property), which is strongly typed and doesn't require casting, and then use something like Jackson to serialize/deserialize it from json, yaml, or xml.
This provides structure to your configuration, and will cause any issues with malformed configurations to show up when you start your application/load your configuration, and not in the middle of your application.
SUBQUESTION: what happens when you MapVariable.put(varToPutIn) many times in a for loop?
A Map represents a mapping. If you do this:
Map<String, Object> map = new HashMap<>();
for (int i = 0; i < 10; i++) {
map.put("myKey", Integer.valueOf(i));
}
what happens is that you add a mapping from "myKey" to zero, then update it to one, two, three and so on. When the loop ends, "myKey" will map to nine.
In short, the map entry for "myKey" is behaving like a variable of type Integer that you assign to repeatedly.
I'm afraid your Gists are telling me that you simply didn't take on board what #Darth Android wrote. Rather that hashing through your code, here's a simple way to parse your config file syntax (more or less) and load it into a Map<String, Object>
Note: I have not compiled or tested this code. It is written to be read and understood, rather than borrowed.
Map<String,Object> config = new HashMap<>();
try (Scanner s = new Scanner(new FileReader(someFile))) {
while (s.hasNext()) {
// Syntax is '<type> <name> is <value>'
String[] words = s.nextLine().split("\\s+");
if (words.length != 4 || !words[2].equals("is")) {
throw MySyntaxException("unrecognizable config");
}
String type = words[0];
String name = words[1];
String val = words[3];
switch (type) {
case "number":
map.put(name, Integer.valueOf(val));
break;
case "boolean":
map.put(name, Boolean.valueOf(val));
break;
case "string":
map.put(name, val);
break;
default:
throw MySyntaxException("unknown type");
}
} catch (NumberFormatException ex) {
throw MySyntaxException("invalid number");
}
}
I need to show on my panel the working dir.
I use String value = System.getProperty("user.dir"). Afterwards i put this string on label but I receive this message on console:
The method getProperty(String, String) in the type System is not applicable for the arguments (String).
I use eclipse.
Issue
I am guessing you have not gone through GWT 101 - You cannot blindly use JAVA CODE on client side.
Explanation
You can find the list of classes and methods supported for GWT from JAVA.
https://developers.google.com/web-toolkit/doc/latest/RefJreEmulation
For System only the following are supported.
err, out,
System(),
arraycopy(Object, int, Object, int, int),
currentTimeMillis(),
gc(),
identityHashCode(Object),
setErr(PrintStream),
setOut(PrintStream)
Solution
In your case Execute System.getProperty("user.dir") in your server side code and access it using RPC or any other server side gwt communication technique.
System.getProperty("key") is not supported,
but System.getProperty("key", "default") IS supported, though it will only return the default value as there is not system properties per se.
If you need the working directory during gwt compile, you need to use a custom linker or generator, grab the system property at build time, and emit it as a public resource file.
For linkers, you have to export an external file that gwt can download and get the compile-time data you want. For generators, you just inject the string you want into compiled source.
Here's a slideshow on linkers that is actually very interesting.
http://dl.google.com/googleio/2010/gwt-gwt-linkers.pdf
If you don't want to use a linker and an extra http request, you can use a generator as well, which is likely much easier (and faster):
interface BuildData {
String workingDirectory();
}
BuildData data = GWT.create(BuildData.class);
data.workingDirectory();
Then, you need to make a generator:
public class BuildDataGenerator extends IncrementalGenerator {
#Override
public RebindResult generateIncrementally(TreeLogger logger,
GeneratorContext context, String typeName){
//generator boilerplate
PrintWriter printWriter = context.tryCreate(logger, "com.foo", "BuildDataImpl");
if (printWriter == null){
logger.log(Type.TRACE, "Already generated");
return new RebindResult(RebindMode.USE_PARTIAL_CACHED,"com.foo.BuildDataImpl");
}
SourceFileComposerFactory composer =
new SourceFileComposerFactory("com.foo", "BuildDataImpl");
//must implement interface we are generating to avoid class cast exception
composer.addImplementedInterface("com.foo.BuildData");
SourceWriter sw = composer.createSourceWriter(printWriter);
//write the generated class; the class definition is done for you
sw.println("public String workingDirectory(){");
sw.println("return \""+System.getProperty("user.dir")+"\";");
sw.println("}");
return new RebindResult(RebindMode.USE_ALL_NEW_WITH_NO_CACHING
,"com.foo.BuildDataImpl");
}
}
Finally, you need to tell gwt to use your generator on your interface:
<generate-with class="dev.com.foo.BuildDataGenerator">
<when-type-assignable class="com.foo.BuildData" />
</generate-with>
I am working on refactoring an existing application written in PowerBuilder and Java and which runs on Sybase EA Server (Jaguar). I am building a small framework to wrap around Jaguar API functions that are available in EA Server. One of the classes is to get runtime statistics from EA Server using the Monitoring class.
Without going into too much detail, Monitoring is a class in EA Server API that provides Jaguar Runtime Monitoring statistics (actual classes are in C++; EA Server provides a wrapper for these in Java, so they can be accessed through CORBA).
Below is the simplified version of my class. (I made a superclass which I inherit from for getting stats for components, conn. caches, HTTP etc).
public class JagMonCompStats {
...
public void dumpStats(String type, String entity) {
private String type = "Component";
private String entity = "web_business_rules";
private String[] header = {"Active", "Pooled", "invoke"};
// This has a lot more keys, simplified for this discussion
private static short[] compKeys = {
(short) (MONITOR_COMPONENT_ACTIVE.value),
(short) (MONITOR_COMPONENT_POOLED.value),
(short) (MONITOR_COMPONENT_INVOKE.value)
};
private double[] data = null;
...
/* Call to Jaguar API */
Monitoring jm = MonitoringHelper.narrow(session.create("Jaguar/Monitoring"));
data = jm.monitor(type, entity, keys);
...
printStats(entity, header, data);
...
}
protected void printStats(String entityName, String[] header, double[] data) {
/* print the header and print data in a formatted way */
}
}
The line data = jm.monitor is the call to Jaguar API. It takes the type of the entity, the name of the entity, and the keys of the stats we want. This method returns a double array. I go on to print the header and data in a formatted output.
The program works, but I would like to get experts' opinion on OO design aspect. For one, I want to be able to customize printStats to be able to print in different formats (for e.g., full blown report or a one-liner). Apart from this, I am also thinking of showing the stats on a web page or PowerBuilder screen, in which case printStats may not even be relevant. How would you do this in a real OO way?
Well, it's quite simple. Don't print stats from this class. Return them. And let the caller decide how the returned stats should be displayed.
Now that you can get stats, you can create a OneLinerStatsPrinter, a DetailedStatsPrinter, an HtmlStatsFormatter, or whatever you want.
The situation seems to be abnormal, but I was asked to build serializer that will parse an object into string by concatenating results of "get" methods. The values should appear in the same order as their "get" equivalent is declared in source code file.
So, for example, we have
Class testBean1{
public String getValue1(){
return "value1";
}
public String getValue2(){
return "value2";
}
}
The result should be:
"value1 - value2"
An not
"value2 - value1"
It can't be done with Class object according to the documentation. But I wonder if I can find this information in "*.class" file or is it lost? If such data exists, maybe, someone knows a ready to use tool for that purpose? If such information can't be found, please, suggest the most professional way of achieving the goal. I thought about adding some kind of custom annotations to the getters of the class that should be serialized.
If you want that you have to parse the source code, not the byte code.
There are a number of libraries that parse a source file into a node tree, my favorite is the javaparser (hosted at code.google.com), which, in a slightly modified version, is also used by spring roo.
On the usage page you can find some samples. Basically you will want to use a Visitor that listens for MethodDefinitions.
Although reflection does not anymore (as of java 7 I think) give you the methods in the order in which they appear in the source code, the class file appears to still (as of Java 8) contain the methods in the order in which they appear in the source code.
So, you can parse the class file looking for method names and then sort the methods based on the file offset in which each method was found.
If you want to do it in a less hacky way you can use Javassist, which will give you the line number of each declared method, so you can sort methods by line number.
I don't think the information is retained.
JAXB, for example, has #XmlType(propOrder="field1, field2") where you define the order of the fields when they are serialized to xml. You can implemenet something similar
Edit: This works only on concrete classes (the class to inspect has its own .class file). I changed the code below to reflect this. Until diving deeper into the ClassFileAnalyzer library to work with classes directly instead of reading them from a temporary file this limitation exists.
Following approach works for me:
Download and import following libarary ClassFileAnalyzer
Add the following two static methods (Attention! getClussDump() needs a little modification for writing out the class file to a temporary file: I removed my code here because it's very special at this point):
public static String getClassDump(Class<?> c) throws Exception {
String classFileName = c.getSimpleName() + ".class";
URL resource = c.getResource(classFileName);
if (resource == null) {
throw new RuntimeException("Works only for concreate classes!");
}
String absolutePath = ...; // write to temp file and get absolute path
ClassFile classFile = new ClassFile(absolutePath);
classFile.parse();
Info infos = new Info(classFile, absolutePath);
StringBuffer infoBuffer = infos.getInfos();
return infoBuffer.toString();
}
public static <S extends List<Method>> S sortMethodsBySourceOrder(Class<?> c, S methods) throws Exception {
String classDump = getClassDump(c);
int index = classDump.indexOf("constant_pool_count:");
final String dump = classDump.substring(index);
Collections.sort(methods, new Comparator<Method>() {
public int compare(Method o1, Method o2) {
Integer i1 = Integer.valueOf(dump.indexOf(" " + o1.getName() + lineSeparator));
Integer i2 = Integer.valueOf(dump.indexOf(" " + o2.getName() + lineSeparator));
return i1.compareTo(i2);
}});
return methods;
}
Now you can call the sortMethodsBySourceOrder with any List of methods (because sorting arrays is not very comfortable) and you will get the list back sorted.
It works by looking at the class dumps constant pool which in turn can be determined by the library.
Greetz,
GHad
Write your custom annotation to store ordering data, then use Method.getAnnotation(Class annotationClass)