map two data structure

F

f

Suppose I have

class Data1{
public String name;
public String address;

public String getName(){
return name;
}

public void setName(String name){
this.name = name;
}

public String getAddress(){
return address;
}

public void setAddress(String address){
this.address = address;
}
}

class Data2{
public String alis;
public String port;

public String getAlis(){
return alis;
}

public void setAlis(String alis){
this.alis = alis;
}

public String getPort(){
return port;
}

public void setPort(String port){
this.port = port;
}
}

class Data3{
public String str1;
public String str1;

public String getStr1(){
return str1;
}

public void setStr1(String str1){
this.str1 = str1;
}

public String getStr2(){
return str2;
}

public void setStr2(String str2){
this.str2 = str2;
}
}

Data1 data1;
Data2 data2;
Data3 data3;

I want to set the attributes in Data3 by the attributes from Data1
or/and Data2. Thus, sometimes I want to do this:

data3.str1 = data2.alis;
data3.str2 = data1.name;

Sometimes I want to do this:

data3.str1 = data1.address;
data3.str2 = data1.name;

Sometimes I want to do this:

data3.str1 = data2.alis;
data3.str2 = data2.port;
....

There is a lot of possible transformations, but at run time, there is
only one used. If I specifiy the mapping in some way, for example, a
xml

<mapping>
<str1 source="data1" attribue="name">
<str2 source="data2" attribue="alis">
</mapping>

My program will read this xml at runtime and do the appropriate
transformation.
Thus, my code will be short. If there a way to do this?
I know I can do it with reflection, how is the perfermance? Any other
ways?

Thanks,

qq
 
A

Alex Hunsley

f said:
Suppose I have

class Data1{
public String name;
public String address;

public String getName(){
return name;
}
[snip]

Not answering your main point here, just a note: your Data classes
should have the member variables being private, e.g.:

class Data1{
private String name;
private String address;

this forces people to go through the get and set methods you've written.
(Think of it this way: what's the point of having getters and setters if
the member variables are public and can be abused as such?)

Once you've made your members vars private,
this code:

data3.str1 = data2.alis;
data3.str2 = data1.name;

should be rewritten as:

data3.setStr1(data2.getAlis());
data3.setStr2(data1.getName());

and so on.

alex
 
A

Alex Hunsley

f said:
Suppose I have

class Data1{
public String name;
public String address;

public String getName(){
return name;
}

public void setName(String name){
this.name = name;
} [SNIP]

Data1 data1;
Data2 data2;
Data3 data3;

I want to set the attributes in Data3 by the attributes from Data1
or/and Data2. Thus, sometimes I want to do this:

data3.str1 = data2.alis;
data3.str2 = data1.name;

Sometimes I want to do this:

data3.str1 = data1.address;
data3.str2 = data1.name;

Sometimes I want to do this:

data3.str1 = data2.alis;
data3.str2 = data2.port;
...

There is a lot of possible transformations, but at run time, there is
only one used. If I specifiy the mapping in some way, for example, a
xml

<mapping>
<str1 source="data1" attribue="name">
<str2 source="data2" attribue="alis">
</mapping>

My program will read this xml at runtime and do the appropriate
transformation.
Thus, my code will be short. If there a way to do this?
I know I can do it with reflection, how is the perfermance? Any other
ways?

Thanks,

Yes, you could use reflection, but with a little redesign you might not
have to.
Rather than having classes with various setters and getters, why don't
you just use Hashmaps?

e.g. Map data1 = new HashMap();
data1.put("ALIS", "blah blah");
data2.put("STR1", "something else");

... and then you can manipulate these hashmaps as you want, given what's
in your xml, without ever using reflection.

example:
instead of doing

data3.str1 = data1.address;

you would do:

data3.put("STR1", data1.get("ADDRESS"));

HTH,
alex
 
A

Alex Hunsley

f said:
Suppose I have

class Data1{
public String name;
public String address;

public String getName(){
return name;
}

public void setName(String name){
this.name = name;
} [SNIP]

Data1 data1;
Data2 data2;
Data3 data3;

I want to set the attributes in Data3 by the attributes from Data1
or/and Data2. Thus, sometimes I want to do this:

data3.str1 = data2.alis;
data3.str2 = data1.name;

Sometimes I want to do this:

data3.str1 = data1.address;
data3.str2 = data1.name;

Sometimes I want to do this:

data3.str1 = data2.alis;
data3.str2 = data2.port;
...

There is a lot of possible transformations, but at run time, there is
only one used. If I specifiy the mapping in some way, for example, a
xml

<mapping>
<str1 source="data1" attribue="name">
<str2 source="data2" attribue="alis">
</mapping>

My program will read this xml at runtime and do the appropriate
transformation.
Thus, my code will be short. If there a way to do this?
I know I can do it with reflection, how is the perfermance? Any other
ways?

Thanks,

Yes, you could use reflection, but with a little redesign you might not
have to.
Rather than having classes with various setters and getters, why don't
you just use Hashmaps?

e.g. Map data1 = new HashMap();
data1.put("ALIS", "blah blah");
data2.put("STR1", "something else");

... and then you can manipulate these hashmaps as you want, given what's
in your xml, without ever using reflection.

example:
instead of doing

data3.str1 = data1.address;

you would do:

data3.put("STR1", data1.get("ADDRESS"));

HTH,
alex
 
P

pete kirkham

In your example, there are at most 16 combinations, so creating a class
that does all these isn't hard- you can even use reflection to generate
the source- and if it's autogenerated, you doen't really care if there
are a thousand or so combinations.

You also could generate the source at runtime from the XML, and compile
and load it, if you are in a situation where javac is available.

Another approach is create the appropriate in bytecodes and load them
with a custom classloader; you should only need to adjust the values in
the constant pool that indicate which fields to use, as in this demo:

import java.io.*;

// interface for something that sets a data 3
public interface Data3Setter {
void setData3 (Data1 data1, Data2 data2, Data3 data3) ;
}

// base implementation
public class Data3SetterImpl implements Data3Setter {
public void setData3 (Data1 data1, Data2 data2, Data3 data3) {
data3.str1 = data2.alis;
data3.str2 = data1.name;
}
}

// creates a dynamic version on Impl based on changing which
// fields are set
public class OnTheFly {
public static void main (String[] args) {
try {
Data1 d1 = new Data1();
Data2 d2 = new Data2();
Data3 d3 = new Data3();

d1.name = "pete";
d1.address = "here";
d2.alis = "the hooded crow";
d2.port = "liverpool";

// load the sample class into a byte array
BufferedInputStream ins = new BufferedInputStream(
new FileInputStream ("Data3SetterImpl.class") );

byte[] classBytes = new byte[(int)
new File("Data3SetterImpl.class").length()];

ins.read(classBytes, 0, classBytes.length);

// find insertion points in constant pool table
byte[][] fieldName = {
"name".getBytes(),
"alis".getBytes() };
int[] nameOffset = new int [fieldName.length];

for (int index=0; index<classBytes.length-4; index++) {
for (int name=0; name<fieldName.length; name++) {
if (nameOffset[name] == 0) {
boolean matches = true;
for (int matchIndex = 0;
matches && matchIndex<fieldName[name].length;
matchIndex++) {
matches = classBytes[index + matchIndex] ==
fieldName[name][matchIndex];
}

if (matches) {
nameOffset[name] = index; //
}
}
}
}

int originalNameLengths = 0;
for (int name=0; name<fieldName.length; name++) {
originalNameLengths += fieldName[name].length;
}

for (int field1 = 0; field1 <2; field1++) {
for (int field2 = 0; field2 <2; field2++) {
fieldName[0] = (field1 == 0 ? "name" : "address").getBytes();
fieldName[1] = (field2 == 0 ? "alis" : "port").getBytes();

byte[] onTheFlyBytes =
new byte[classBytes.length - originalNameLengths +
fieldName[0].length + fieldName[1].length];

// need to set the data in the right order
int firstName;
int secondName;

if (nameOffset[0] > nameOffset[1]) {
firstName = 1;
secondName = 0;
} else {
firstName = 0;
secondName = 1;
}

// copy before name
System.arraycopy(classBytes, 0, onTheFlyBytes, 0,
nameOffset[firstName]-1);

// copy new name and length
onTheFlyBytes[nameOffset[firstName]-1] =
(byte)fieldName[firstName].length;
System.arraycopy(fieldName[firstName], 0, onTheFlyBytes,
nameOffset[firstName], fieldName[firstName].length);

// copy after name
int originalOffset = nameOffset[firstName] + 4;
int copyOffset = nameOffset[firstName] +
fieldName[firstName].length;

System.arraycopy(classBytes, originalOffset, onTheFlyBytes,
copyOffset, nameOffset[secondName]-nameOffset[firstName]-5);

// copy new name
copyOffset += nameOffset[secondName]-nameOffset[firstName] -
fieldName[firstName].length;
originalOffset = nameOffset[secondName];
onTheFlyBytes[copyOffset-1] =
(byte)fieldName[secondName].length;
System.arraycopy(fieldName[secondName], 0, onTheFlyBytes,
copyOffset, fieldName[secondName].length);
copyOffset += fieldName[secondName].length;
originalOffset += 4;

// copy rest
System.arraycopy(classBytes, originalOffset, onTheFlyBytes,
copyOffset, classBytes.length - originalOffset);

// DynamicClassLoader is simple extension of ClassLoader
// that provides public method to define class
Class helperClass = new
DynamicClassLoader().defineDynamicClass(
"Data3SetterImpl", onTheFlyBytes);

Data3Setter setter = (Data3Setter)helperClass.newInstance();

setter.setData3(d1, d2, d3);

System.out.println((field1 == 0 ? "name" : "address") + ", " +
(field2 == 0 ? "alis" : "port") + " => " +
d3.getStr1() + ", " + d3.getStr2());
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

Pete
 
A

Alex Hunsley

f said:
Any ideas? As a modern language, java must have some ways to do this.

Thanks,

ff
[snip all of code posted again]

Well, I sent you my reply. Have you read that?
Also, please try to trim your replies as appropriate - you've reposted
your entire original post whith your (top-posted) reply, which is
unneccesary.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,430
Messages
2,571,676
Members
48,796
Latest member
Greg L.

Latest Threads

Top