parsing a file to create objects in java - java

I have a file with is the output of an trading agent's activities. For example:
222666:org.powertac.common.Order::171875::new::21::165482::-35.74395569719625::35.0
222666:org.powertac.common.Order::171876::new::21::165893::-35.74395569719625::35.0
The class Order is defined as:
public Order (Broker broker, Timeslot timeslot,
double mWh, Double limitPrice)
{
super();
this.broker = broker;
this.timeslot = timeslot;
this.mWh = mWh;
this.limitPrice = limitPrice;
}
so from the file I have:
<id>:<package_name>::<execution_id>::<new object>::<args_list>
However, there is some examples like:
222665:org.powertac.genco.Genco::21::setCurrentCapacity::35.74395569719625
222665:org.powertac.genco.Genco::21::setInOperation::true
so instead of creating a new object, I have to call the method setCurrentCapacity with the 35.7439.. parameter.
My goal is to create a
Map<Integer, Object> map = new Map<Integer, Object>();
that's it, a Map between Integer id and Object. Thus, if I want to reproduce the agent activity again, I would just process the Map Object. I was wondering what would be the best approach to achieve my goal. Do I have to actually create the Genco object, for example, and cast it to Object before storing on the Map? How do I set the function call? I mean, how do I create the Genco object and tell it to call setInOperation in the Map? Also, what does it mean and how could I handle values like:
300:org.powertac.du.DefaultBrokerService$LocalBroker::1::new::default broker
300:org.powertac.du.DefaultBrokerService$LocalBroker::1::setLocal::true
with the $ symbol?

The dollar sign is a valid character in a class name, but by convention its use is discouraged. In practice, it can show up for numerous reasons. In your scenario, it is likely that LocalBroker is an inner class of DefaultBrokerService.
From the JLS§3.8:
The "Java letters" include uppercase and lowercase ASCII Latin letters
A-Z (\u0041-\u005a), and a-z (\u0061-\u007a), and, for historical
reasons, the ASCII underscore (_, or \u005f) and dollar sign ($, or
\u0024). The $ character should be used only in mechanically generated
source code or, rarely, to access pre-existing names on legacy
systems.

I was wondering what would be the best approach to achieve my goal. Do
I have to actually create the Genco object, for example, and cast it
to Object before storing on the Map?
Genco is already an Object. You don't need to cast it. All classes inherits from Object in Java. Just insert it in the map.
yourMap.put( 1234, gencoObj );
I mean, how do I create the Genco object and tell it to call
setInOperation in the Map?
Get the object via its id (your map key), cast it to the apropriate type and call the desired method.
Object o = yourMap.get( 1234 );
if ( o instanceof Genco ) {
Genco g = ( Genco ) o;
g.methodToBeCalled();
}
The $ sign is used by the Java compiler to name nested classes. So, in your case, LocalBroker is a nested class of DefaultBrokerService.
Compiling this:
public class Foo {
private class Bar {
}
}
Will generate two .class files: Foo.class and Foo$Bar.class.
Edit: to store the method parameters you can do something like:
// considering this class
public class Genco {
...
public void methodToBeCalled( Double param ) {
// do something
}
}
// in another class...
// storing the parameters using a String as a key
// representing the object id + the name of the method to be called
Map<String, Object[]> params = new HashMap<String, Object[]>();
// for methodToBeCalled of the object with id equals to 1234
// store a new array of objects with an 2.5 Double (autoboxing will apply here, i.e.,
// the double 2.5 will be wrapped in a Double
params.put( "1234-methodToBeCalled", new Object[]{ 2.5 } );
// now, using...
int objectId = 1234;
// get the object
Object o = yourMap.get( objectId );
// verify if it is an instance of Genco
if ( o instanceof Genco ) {
// yes, it is, so cast it to Genco to be able
// to call Genco specific methods
Genco g = ( Genco ) o;
// getting the parameters (objectId + method name)
Object p = params.get( objectId + "-methodToBeCalled" );
// calling the method, passing the first value of the stored array (2.5)
g.methodToBeCalled( ( Double ) p[0] );
}

Related

How to get the values of specific fields in a Map<String, Object>

I have something like:
Map<String, Object> hashMap;
When I do something like:
hashMap.get("binary"), I get value as: {size=5642, name=abc}
Here key is binary and value is an Object of Type Object and is {size=5642, name=abc}
Note the values dont belong to a particular class.
In Python I can do something like hashMap["binary"]["size"], was wondering what would be the equivalent in java
How do I get the value of size directly without parsing the above string?
The value is not of Type Object, but of some type that extends from Object (in java everything extends Object implicitly). Let's call it "X"
Now, it doesn't work like python because unlike python java doesn't have that dynamic nature.
{size=5642, name=abc} is probably a string representation of that type X. This is what you see in a debugger or maybe when trying to print the value on console with System.out.println or something.
Now first of all figure out which type is it:
Object value = hashMap.get("binary")
System.out.println(value.getClass().getName());
It will print the class name
Then check the source of that class, probably it looks like this:
public class X {
private final int size;
private final String name;
... // constructor, other stuff maybe
// these are called "getters" in java world
public int getSize() {return size;}
public String getName() {return name;}
}
From that point you have 2 ways to get the size:
Object value = hashMap.get("binary");
int size = ((X)value).getSize(); // This is called downcasting
The drawback of this method is that you don't utilize the power of generics
So the better option is a refactoring if its possible of course:
Map<String, X> hashMap = ...
X value = hashMap.get("binary");
value.getSize();
One final note:
If it happens that the value is of type String, you won't be able to get the size other than parsing the value with regular expression or something. In this case consider a refactoring as a better option.

Return multiple values to an Oracle java function using types

Unable to return multiple values to an Oracle function from java using an Oracle type
I've created an oracle type & function to call a java method with the simple purpose of swapping the values of the two fields I have in the Oracle type. Everything compiles just fine, but when I execute the function in Oracle I just receive the original type values.
In Oracle:
create or replace type swapper_in as object (
a varchar2(20),
b varchar2(20) );
create or replace function swapstring (s swapper_in) return swapper_in
as language java
name 'swapperstring.swap(java.sql.Struct) return java.sql.Struct';
public class swapperstring
{
public static java.sql.Struct swap( java.sql.Struct i )
{
Object[] attribs=null;
attribs = i.getAttributes();
attribs[0] = attribs[1];
return i;
}
}
declare
s swapper_in
o swapper_in
begin
s := swapper_in('String One', 'String Two');
dbms_output.put_line( s.a );
dbms_output.put_line( s.b );
select swapstring(s) into o from dual;
dbms_output.put_line( o.a );
dbms_output.put_line( o.b );
end;
Output:
String One
String Two
String One
String Two
Since I set the first attribute to equal the second in the java code I would expect the output to be String Two for both fields in the output. But it appears it is returning the original object unmodified.
How do I modify attributes of a java.sql.Struct or create a new object with modified attributes?

How I can send custom parameters through java?

Suppose I want to send following parameters :
key1: value1,
key2: value2
But currently I can't decide what will be there at place of key1,key2
That may be any string. key1 may be city,key2 may be code. Or key 1 may be companyName and key 2 is domain. So how can I set any custom unknown parametrs in method of java? Consider that I know total number of parameters and data type of their values, but can't determine their exact keys now. How to implement it in java?
You can send an array of objects in your method:
Object[] myObjects = new Object[2];
myObjects[0] = "This is a string";
myObjects[1] = 5;
myMethod(myObjects);
public void myMethod(Object[] myObjects){
// DoSomethingOverHere
}
If you only have Strings you can do the same but specify an array of Strings instead of objects. If you use objects, make sure to check the instance of the objects before using it.
I assume what you mean to achieve is a method that can accept any type of argument and still do the work.
Below is the approach I would use:
Lets say you want to use myMethod:
class MainClass {
public Object myMethod(Object A,Object B)
{
Object C=(Object) (A.toString()+","+B.toString());
System.out.println(C.toString());
return C;
}
}
And you can call it with any type of parameters:
public class TesterClass {
MainClass mainClass=new MainClass();
mainClass.myMethod(123, "PQR");
mainClass.myMethod(123.00, "PQR");
mainClass.myMethod(123.00, 123);
mainClass.myMethod(new int[]{1,2,3}, "PQR");
}
Your output will be:
123,PQR
123.0,PQR
123.0,123
[I#659e0bfd,PQR
last one is array, you can manipulate its processing)

converting List<String> to Object

In my current project, I want to convert List<String> to RegionLabel Object.
For instance, User enters String value one by one in order -- center, floor, room . I am storing user's input into List.
Now, my internal data structure in RegionLabel( String centerString, String floorString, String roomString);
My requirement is to convert List<String> data structure into RegionLabel("center", floor", "room" ); data structure.
One note:
My RegionLabel class is generated on-fly. On-fly means at design time, I do not know that "how many arguments RegionLabel constructors have?"
-Pankesh
Perhaps you're just after
new RegionLabel(list.get(0), list.get(1), list.get(2))
I do not know that "how many arguments RegionLabel constructors have?"
Then you'll have to use reflection, or provide a constructor that accepts a List<String> as argument.
Create a new constructor like RegionLabel(List<String> list). This should do.
public RegionLabel(List<String> list) throws Exception{
if( null == list || list.size() < 3 )
throw new Exception("illegal parameter");
this.centre = list.get(0);
...
}
RegionLabel label = new RegionLabel(inputList.get(0), inputList.get(1), inputList.get(2));
Simplified without any errorhandling or validation but without any more constraints on your "conversion", it's hard to be more generic.

What's the proper way to use reflection to instantiate objects of unknown classes at runtime?

I am working on a Configuration Loader class so that I can change the parameters of my program via an external text file (config.txt) rather than having to recompile my code with every change I make.
It has been suggested that I use Java's Reflection to do this, but I'm a little confused as to how I might actually implement this.
I have been able to successfully extract the class name and the arguments for its constructor from my text file, but how do I go from this to an instantiated object?
here's what I have of my method so far:
public void loadObject(String classString, HashMap hm)
{
String className = props.getProperty(classString);
Class c = Class.forName(className);
}
classString is a string containing the name of the class, and hm is a hashmap where the class' constructor parameters map to their intended values.
I.e., for class Foo (int xPos, float yPos), "xPos" would map to a string of the intended int, and "yPos" maps to a string of the intended float. I want to be able to return, new Foo(hm.get"xPos".toInt, hm.get"yPost".toFloat), but I'm unsure how to dynamically use a constructor like that (the issue is, there are multiple possible classes -- perhaps it's a bar instead of a foo, for instance).
I know that its possible to do an if/else based off the classString, and simply call the proper constructor after identifying it that way, but I am looking to create a more extensible code that doesn't have to be rewritten every time I add a new class to the program.
All of the possible objects inherit from a single parent object.
You would use Class.getConstructor(Class<?>... parameterTypes) to get a reference to the constructor followed by Constructor.newInstance(Object... initargs).
However I would suggest taking a look at a dependency injection framework such as Spring or Guice as it sounds like what you are creating is a basic version of what they do.
Upon request for expanding this answer:
Class c = Class.forName(name);
Constructor ctor = c.getConstructor(Integer.class, Integer.class);
Integer param1 = hm.get("xPos") ...;
Integer param2 = hm.get("yPos") ...;
Object instanceOfTheClass = ctor.newInstance(param1, param2);
Of course instead of param1 and param2 you would create an array of arguments based upon what was in the input file (the same goes for the arguments to getConstructor()), etc.
Here's an example of doing it from program arguments:
import java.lang.reflect.Constructor;
import java.util.*;
public class InstantiateWithReflectionIncludingArgs {
public static void main(String[] args) throws Exception {
String className = args[0];
List<Object> argList = new ArrayList<Object>();
if (args.length > 1) {
argList.addAll(Arrays.asList(args).subList(1, args.length));
}
Class c = Class.forName(className);
List<Class<?>> argTypes = new ArrayList<Class<?>>();
for (Object arg : argList) {
argTypes.add(arg.getClass());
}
Constructor constructor = c.getConstructor(
argTypes.toArray(new Class<?>[argTypes.size()]));
Object o = constructor.newInstance(
argList.toArray(new Object[argList.size()]));
System.out.println("Created a " + o.getClass() + ": " + o);
}
}
Naturally, the argList can only ever have Strings in this case because they're pulled from a String[], but you could add args of any type. Note that constructor args are positional, not named, so the names in the map won't do you much good. They need to be in the proper order.
Try running it and passing "java.util.Date" as an argument.
Class<?> clazz = MyClass.class;
Constructor<?> ctor = clazz.getConstructor( /* Array of Classes the constructor takes */);
ctor.newInstance( /* arguments the constructor takes */ );

Categories