1

XML:

<data_format>
    <data_length>15</data_length> <!-- -1 for unknown -->
    <start_charater>$</start_charater>
    <end_character1>B</end_character1>
    <end_character2>E</end_character2>
    <no_of_parameter>2</no_of_parameter>
    <parameter>
        <start_charater>A</start_charater>
        <data_name>Azimuth</data_name>
        <data_type>char</data_type>
        <size>5</size>
    </parameter>
    <parameter>
        <start_charater>R</start_charater>
        <data_name>Range</data_name>
        <data_type>char</data_type>
        <size>5</size>
    </parameter>
</data_format>

How should I convert this information encoded in XML into a class which can contain this structure? I need this to be done at runtime. I am getting the data for Azimuth and Range from a packet received through some port and need a structure to hold that data which I don't want to hard code but want to produce it at runtime when in parse that XML. the purpose for doing this is to increase the generic nature of my application.

Example :

<!-- for this xml -->
  <data>
    <data_member name="name" type="String"></data_member>
    <data_member name="id" type="int"></data_member>
  </data>

And the Java class that i want is:

class Data
  {
     private String name;
     private int id;
     public String getName()
      {
        return name;
      }
      public void setName(name)
      {
        this.name=name;
      }
      public int getId()
      {
        return id;
      }
      public void setId(id)
      {
        this.id=id;
      }
}
Betlista
  • 10,327
  • 13
  • 69
  • 110
  • Do you have an XML schema which defines the structure of that XML? If a class is created at runtime, how can you call its methods? – VGR Jul 19 '17 at 14:35
  • 1
    Can you add a class definition you want to be created dynamically? But I'm afraid you cannot say something like "I want new class DataHolder extending Object with fields a, b and c" created dynamically. Please specify better what you want to achieve... – Betlista Jul 19 '17 at 14:43
  • do you want to create a simple Java Bean Object which contains two attributes? – Michael Meyer Jul 19 '17 at 14:44
  • No sir,I don't have any schema of this XML. I actually don't know how to create a schema for an XML file. I actually want to make a code which could enhance the genricness. I don't want to hardcode the java class every time i get another structure through XML. I need a solution which can make a class for me at runtime and have those data_name defined in XML as data members in the class and their getter and setters. @VGR – Prabhnoor Singh Jul 19 '17 at 14:48
  • I have no idea, how the rest of your application can work with such instances. All you know about it is, that it is an object, nothing more... – Betlista Jul 19 '17 at 14:53
  • At the very least, edit your question and show some example code, so we understand how you expect to use such a “generic” class. – VGR Jul 19 '17 at 14:57
  • If the names of data members can be same as that of data_name in the XML file then i could use it through their getter setter. Is it possible this way? – Prabhnoor Singh Jul 19 '17 at 14:59
  • 1
    Found [this](https://stackoverflow.com/questions/5178391/create-simple-pojo-classes-bytecode-at-runtime-dynamically) but not sure how it helps. How would the rest of your code know how to call the methods of this dynamically generated class? Please add more context and describe the use case in detail. – Andrew S Jul 19 '17 at 15:00
  • @VGR i have edited my question. – Prabhnoor Singh Jul 19 '17 at 15:19
  • 1
    I think you are off to the wrong direction here. You are asking for something which is very difficult and not very useful. And it's still not clear how you will know the name of the getter and setter you will need to access. If you somehow know the names in the XML, you may well use a `Map` of some sort. Why do you need a class? – RealSkeptic Jul 19 '17 at 15:21
  • Four people, including myself, have asked you how your code will know to call a method like `getName` when you don’t know what methods exist in the class until runtime. Please address that question. – VGR Jul 19 '17 at 15:23
  • @VGR i think that will give an error because that doesn't exist yet. – Prabhnoor Singh Jul 19 '17 at 15:27
  • Exactly. Even if you could generate a class from unknown XML, you wouldn’t be able to use it. So why exactly do you want to generate such a class? What do you plan to do with it? – VGR Jul 19 '17 at 15:30
  • @RealSkeptic could you explain your idea a little bit more because what i need is to receive a packet, apply some conversion on the data received, packetise again and send it to a port. NOW i will not have only one XML but many and i want a single piece of code that can handle all the XMLs for the same purpose. – Prabhnoor Singh Jul 19 '17 at 15:31
  • What you're attempting to do is ineffective and difficult to implement. Using a library like [JAXB](http://www.oracle.com/technetwork/articles/javase/index-140168.html) will help you take XML files and turn them into (already written) POJOS. – Austin Schaefer Jul 19 '17 at 15:31
  • What can other classes beneath the 'data' class be? Do you have another example? – Supahupe Jul 19 '17 at 15:34
  • @AustinSchäfer could you explain what is done [here](https://www.youtube.com/watch?v=RSmwdijv_M0&t=23s) – Prabhnoor Singh Jul 19 '17 at 15:37
  • 1
    This sounds a lot like an [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem/66378#66378). Now that we know you want to change some parts of the XML document, we can address *that* question. Most likely, you want to simply navigate the XML [Document](http://docs.oracle.com/javase/8/docs/api/org/w3c/dom/Document.html), or, if the XML is very large, use [XSLT](https://www.w3.org/TR/xslt) to [transform](http://docs.oracle.com/javase/8/docs/api/javax/xml/transform/Transformer.html#transform-javax.xml.transform.Source-javax.xml.transform.Result-) it. – VGR Jul 19 '17 at 15:57
  • @VGR XMLs that i have just contain the structure for the fields or parameters sent by sensors(from where i am getting data in the form of packets) and i don't want to store the data into the XMLs(i am using XML for defining structure only so that if a new sensor is added in future,people can create an XML for the same which is easier than coding and can use my application to test the sensors) and ultimately i need to receive a packet, apply some conversion on the data received, packetise again and send it to a port. NOW i will not have only one XML but many.I need something generic for this. – Prabhnoor Singh Jul 19 '17 at 16:16
  • @VGR And if somehow a class is created dynamically ,can't the methods be called anyhow using reflection ? – Prabhnoor Singh Jul 19 '17 at 16:38
  • 1
    Even if you use reflection, how will you know which methods to call? How will you know what data the get-methods return, or what data to pass to a set-method? I think your design is flawed. You cannot reasonably tell people “send anything you want and I’ll figure it out.” You need to define a specific structure and you need to require others to adhere to it. This is why public methods exist. And it’s why XML schemas exist. Without a well-defined contract for communication, you will have unreliable, unrobust guesswork at best. – VGR Jul 19 '17 at 16:42
  • @VGR data types are already defined in the xml ,xml contains proper structure and all other information it requires.we know the data type because we will the one designing the xml at the first place. – Prabhnoor Singh Jul 19 '17 at 16:47

2 Answers2

3

Save yourself a headache: create your POJOs manually, and use JAXB to process relevant XML files into your POJO instances. See this question for an example and a reference link.

Austin Schaefer
  • 695
  • 5
  • 19
0

Let's start with second XML example, which is btw a lot different to a first one...

Here it is again (in case of edit, I added values to XML):

<data>
    <data_member name="name" type="String">foo</data_member>
    <data_member name="id" type="int">42</data_member>
</data>

As RealSkeptic mentioned in a comment, you can use Maps:

import java.util.HashMap;
import java.util.Map;

public class DataHolder {

    private Map<String, Integer> ints = new HashMap<>();
    private Map<String, String> strings = new HashMap<>();

    public int getInt(String fieldName) {
        return ints.get(fieldName);
    }

    public void setInt(String fieldName, int value) {
        ints.put(fieldName, value);
    }

    public String getString(String fieldName) {
        return strings.get(fieldName);
    }

    public void setString(String fieldName, String value) {
        strings.put(fieldName, value);
    }

}

I'd strongly recommend to use only some well known types: primitives + String seems reasonable for a start. Do not use Object's, that's always painful to work with that, at some point I need to cast it to something specific.

But still if I'm the user of your API, I'd create wrapper class to work with it in more convenient way:

public class DataHolderNameAndIdWrapper {

    private DataHolder dataHolder;

    public void setDataHolder(DataHolder dataHolder) {
        this.dataHolder = dataHolder;
    }

    public String getName() {
        return dataHolder.getString("name");
    }
    public void setName(String name) {
        dataHolder.setString("name", name);
    }
    public Integer getId() {
        return dataHolder.getInt("id");
    }
    public void setId(Integer id) {
        dataHolder.setInt("id", id);
    }

}

Because me as a consumer I want to know what am I working with and I personally do not agree with your comment "people can create an XML for the same which is easier than coding", as you see, discussion is longer, then proper implementation...

There are still some questions

  • Do you want the names to be case sensitive?
  • What will happen if it is not set?

While java is case sensitive, for usage above I'd convert field names to lowercase. Maps will return nulls if not there. I'd again return empty string "" or 0.

Betlista
  • 10,327
  • 13
  • 69
  • 110