Using an XmlAdapter

4 篇文章 0 订阅

当使用JAXB绑定数据(把对象转换成XML,或把XML转换成对象)时,一些数据类型是转换不了的,例如Map,一些没有默认构造函数的类。

当想绑定这样的数据类型时,需要写一个转换类进行转换。

转换类的主要想法就是,把不能转换的类型按我们规定的格式,转换成能够JAXB能够转换的类型,进行传输等操作。

在接收或处理方,再通过JAXB把数据按照我们规定的格式,再转换成我们原来的类型(也就是JAXB不能转换的类型)。

就像下面的例子中的Currency类,把Currency类转换成String类(String可以被JAXB在绑定的数据类型);然后,在接收或处理方,又把String转换成了Currency类。

http://www.eclipse.org/eclipselink/documentation/2.6/moxy/advanced_concepts006.htm

Using an XmlAdapter

Some Java classes may not be well suited for use with JAXB and at first glance may seem "unmappable" – for example, classes that do not have a default no-arg constructor, or classes for which an XML representation cannot be automatically determined. Using JAXB's XmlAdapter, you can define custom code to convert the unmappable class into something that JAXB can handle. Then, you can use the @XmlJavaTypeAdapter annotation to indicate that your adapter should be used when working with the unmappable class.

XmlAdapter uses the following terminology:

  • ValueType – The type that JAXB knows how to handle out of the box.

  • BoundType – The type that JAXB doesn't know how to handle. An adapter is written to allow this type to be used as an in-memory representation through the ValueType.

The outline of an XmlAdapter class is as follows:

Example 8-32 XmlAdapter Class Outline

public class AdapterName extends XmlAdapter<ValueType, BoundType> {
 
   public BoundType unmarshal(ValueType value) throws Exception {
      ...
   }
 
   public ValueType marshal(BoundType value) throws Exception {
      ...
   }
 
}
 

Using java.util.Currency

Our first example will use the following domain class:

Example 8-33 Sample Domain Class

package example;
 
import java.util.Currency;
 
import javax.xml.bind.annotation.*;
 
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class PurchaseOrder {
 
   private Double amount;
 
   private Currency currency;
 
   ...
}
 

Here, the Currency cannot be automatically mapped with JAXB because it does not contain a no-argument constructor. However, we can write an adapter that will convert the Currency into something that JAXB does know how to handle – a simple String. Luckily, in this case the Currency's toString() method returns the currency code, which can also be used to create a new Currency:

Example 8-34 Using an Adapter

package example;
 
import java.util.Currency;
 
import javax.xml.bind.annotation.adapters.XmlAdapter;
 
public class CurrencyAdapter extends XmlAdapter<String, Currency> {
 
   /*
    * Java => XML
    * Given the unmappable Java object, return the desired XML representation.
    */
   public String marshal(Currency val) throws Exception {
      return val.toString();
   }
 
   /*
    * XML => Java
    * Given an XML string, use it to build an instance of the unmappable class.
    */
   public Currency unmarshal(String val) throws Exception {
      return Currency.getInstance(val);
   }
 
}
 

To indicate that our adapter should be used for the Currency property, we annotate it with @XmlJavaTypeAdapter and provide the class name of our adapter:

Example 8-35 Using the @XmlJavaTypeAdapter Annotation

package example;
 
import java.util.Currency;
 
import javax.xml.bind.annotation.*;
 
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class PurchaseOrder {
 
   private Double amount;
 
   @XmlJavaTypeAdapter(CurrencyAdapter.class)
   private Currency currency;
 
   ...
}
 

Using java.awt.Point

Sometimes the best way to handle an unmappable class is to write a "stand-in" class which can be mapped with JAXB, and convert between the two classes in the XmlAdapter. In this example, we want to use the Point class. Because of that class' getLocation() method (which JAXB will pickup automatically and map), an infinite loop will occur during marshalling. Because we cannot change the Point class, we will write a new class, MyPoint, and use it in the adapter.

Example 8-36 Using java.awt.Point

package example;
 
public class MyPoint {
 
   private int x, y;
 
   public MyPoint() {
      this(0, 0);
   }
 
   public MyPoint(int x, int y) {
      this.x = x;
      this.y = y;
   }
 
   public int getX() {
      return x;
   }
 
   ...
}
 
package example;
 
import java.awt.Point;
 
import javax.xml.bind.annotation.adapters.XmlAdapter;
 
public class MyPointAdapter extends XmlAdapter<MyPoint, Point> {
 
   /*
    * Java => XML
    */
   public MyPoint marshal(Point val) throws Exception {
      return new MyPoint((int) val.getX(), (int) val.getY());
   }
 
   /*
    * XML => Java
    */
   public Point unmarshal(MyPoint val) throws Exception {
      return new Point(val.getX(), val.getY());
   }
 
}
 

Finally, our Point properties are marked with @XmlJavaTypeAdapter:

Example 8-37 Using the @XmlJavaTypeAdapter Annotation

package example;
 
import java.awt.Point;
 
import javax.xml.bind.annotation.*;
 
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Zone {
 
   private String name;
 
   @XmlJavaTypeAdapter(MyPointAdapter.class)
   private Point startCoord;
 
   @XmlJavaTypeAdapter(MyPointAdapter.class)
   private Point endCoord;
 
   ...
}

Specifying Package-Level Adapters

In Example 8-37, we annotated both Point properties with the @XmlJavaTypeAdapter annotation. If you have many of these types of properties – for example, in other domain classes – it can be more convenient to specify the @XmlJavaTypeAdapters at the package level.

We could define both of the adapter classes in package-info.java, and would no longer have to annotate any further Currency or Point properties:

@XmlJavaTypeAdapters({
   @XmlJavaTypeAdapter(value=CurrencyAdapter.class,type=Currency.class),
   @XmlJavaTypeAdapter(value=MyPointAdapter.class,type=Point.class)
})
package example;
 

Specifying Class-Level @XmlJavaTypeAdapters

If you have a Java class and you would like to always use an XmlAdapter during marshalling and unmarshalling, then you can specify the @XmlJavaTypeAdapter directly at the class level:

package example;
 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
@XmlJavaTypeAdapter(DataStructureAdapter.class)
public class DataStructure {
 
   ...
 
}
 

Now, any object that has a DataStructure property will automatically use the DataStructureAdapter, without the need for an annotation on the property itself.



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Great! Here are the steps to design a system in Tinkercad for measuring distances using an Ultrasonic rangefinder: 1. Open Tinkercad and create a new project. 2. Add an Arduino board to your project by dragging it from the components panel to the workplane. 3. Next, add an Ultrasonic rangefinder sensor to your project. You can find the sensor in the components panel under "Sensors". 4. Connect the Ultrasonic rangefinder to the Arduino board using jumper wires. Connect the VCC pin to the 5V pin on the Arduino board, the GND pin to the GND pin on the Arduino board, the TRIG pin to pin 9 on the Arduino board, and the ECHO pin to pin 10 on the Arduino board. 5. Write the code to measure distances using the Ultrasonic rangefinder and display the results on the Serial Monitor. Here is an example code: ``` const int trigPin = 9; const int echoPin = 10; void setup() { Serial.begin(9600); pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); } void loop() { digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); long duration = pulseIn(echoPin, HIGH); float distance = duration * 0.034 / 2; Serial.print("Distance: "); Serial.print(distance); Serial.println(" cm"); delay(1000); } ``` 6. Upload the code to the Arduino board by clicking the "Code" button in the top menu and selecting "Upload to Arduino". 7. Open the Serial Monitor by clicking the "Serial Monitor" button in the top menu. You should see the distance measurements displayed in the Serial Monitor. That's it! You have now designed a system in Tinkercad for measuring distances using an Ultrasonic rangefinder.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值