intra-mart Accel Platform TERASOLUNA Server Framework for Java (5.x) プログラミングガイド 第16版 2019-12-01

ConfigurationLoader 使用時の注意事項

概要

ConfigurationLoader#load or #loadAll メソッドを使用するにあたって注意すべき点について説明します。

注意事項

ConfigurationLoader#load or #loadAll メソッドは、JAXB(Java Architecture for XML Binding)を利用して設定ファイルから
データを読み込んでいるため、使用するには設定ファイル、スキーマ定義、および、スキーマ定義に基づいたクラスが必要となります。
しかし、JAXB を利用してスキーマ定義から自動生成したクラスをConfigurationLoader で使用すると ThreadLocal が開放されずに
メモリリーク します。
ConfigurationLoader を使用して設定ファイルを読み込む場合はスキーマ定義から自動生成したクラスを修正してください。

スキーマ定義から自動生成したクラスの修正

修正対象

スキーマ定義から自動生成したクラスがメモリリークしないようにするため、以下のクラスを修正する必要があります。
  • @XmlRegistry アノテーションが付与されているクラス
  • @XmlType アノテーションが付与されているクラス

修正方法

@XmlRegistry アノテーションが付与されているクラスの修正

インスタンスを生成しているメソッドを static メソッド に修正してください。
通常は自動生成時に @XmlType アノテーションが付与されているクラスのインスタンスを生成するメソッドが定義されていますが
不足している場合はインスタンスを生成して返却する static メソッドを作成してください。
@XmlRegistry
public class ObjectFactory {

    public static JaxbConfig createJaxbConfig() {
        return new JaxbConfig();
    }

    public static JaxbConfig.JaxbNestedConfig createJaxbConfigJaxbNestedConfig() {
        return new JaxbConfig.JaxbNestedConfig();
    }

}

コラム

自動生成時のインスタンス生成メソッドは以下の命名規則に従って定義されます。
  • クラス名の先頭に「create」を加えた「create(クラス名)」で定義されます。
  • ネストクラスに @XmlType アノテーションが付与されている場合は
    「create(外側のクラス名)(ネストクラス名)」で定義されます。

@XmlType アノテーションが付与されているクラスの修正

@XmlType アノテーションに factoryClass、および、factoryMethod を指定してください。
  • factoryClass
    同一パッケージ内のクラスから @XmlRegistry アノテーションが付与されているクラスを指定してください。
  • factoryMethod
    factoryClass で指定したクラスのメソッドから自身のインスタンスを生成するメソッドを文字列で指定してください。
@XmlType(name = "", propOrder = {
    "jaxbNestedConfig"
}, factoryClass = ObjectFactory.class , factoryMethod = "createJaxbConfig")
@XmlRootElement(name = "jaxb-config")
public class JaxbConfig {

    @XmlType(name = "", propOrder = {
        "value"
    }, factoryClass = ObjectFactory.class , factoryMethod = "createJaxbConfigJaxbNestedConfig")
    public static class JaxbNestedConfig {

修正例

以下のスキーマ定義から自動生成されたクラスの修正例を示します。

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
  targetNamespace="http://intra_mart.co.jp/jaxb/sample/jaxb-config"
  xmlns:tns="http://intra_mart.co.jp/jaxb/sample/jaxb-config"
  xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0"
  elementFormDefault="qualified">
  
    <xs:annotation>
        <xs:appinfo>
            <jaxb:schemaBindings>
                <jaxb:package name="jp.co.intra_mart.jaxb.sample" />
            </jaxb:schemaBindings>
        </xs:appinfo>
    </xs:annotation>

    <xs:element name="jaxb-config">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="jaxbNestedConfig">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="value" type="xs:string" />
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

</xs:schema>

@XmlRegistry アノテーションが付与されているクラス

自動生成時はメソッドに static 修飾子がありません。処理内容は変更せず、static メソッドに修正するのみです。

自動生成時
package jp.co.intra_mart.jaxb.sample;

import javax.xml.bind.annotation.XmlRegistry;

@XmlRegistry
public class ObjectFactory {

    public ObjectFactory() {
    }

    public JaxbConfig createJaxbConfig() {
        return new JaxbConfig();
    }

    public JaxbConfig.JaxbNestedConfig createJaxbConfigJaxbNestedConfig() {
        return new JaxbConfig.JaxbNestedConfig();
    }

}

修正例
package jp.co.intra_mart.jaxb.sample;

import javax.xml.bind.annotation.XmlRegistry;

@XmlRegistry
public class ObjectFactory {

    public ObjectFactory() {
    }

    public static JaxbConfig createJaxbConfig() {
        return new JaxbConfig();
    }

    public static JaxbConfig.JaxbNestedConfig createJaxbConfigJaxbNestedConfig() {
        return new JaxbConfig.JaxbNestedConfig();
    }

}

@XmlType アノテーションが付与されているクラス

自動生成時は @XmlType アノテーションに factoryClass , factoryMethod の指定がありません。
@XmlType アノテーションは JaxbConfig クラス、および JaxbNestedConfig クラスに付与されているため
二箇所 factoryClass , factoryMethod を指定する修正が必要です。
  • factoryClass
    @XmlRegistry アノテーションは ObjectFactory クラスに付与されているため、両クラスとも
    @XmlType アノテーションの factoryClass には「factoryClass = ObjectFactory.class」と指定します。
  • factoryMethod
    ObjectFactory クラスには両クラスのインスタンスを生成するメソッドが定義されているため
    各 @XmlType アノテーションの factoryMethod に自身のインスタンスを生成するメソッドを指定します。
    JaxbConfig クラスは「factoryMethod = “createJaxbConfig”」と指定します。
    JaxbNestedConfig クラスは「factoryMethod = “createJaxbConfigJaxbNestedConfig”」と指定します。

    自動生成時
    package jp.co.intra_mart.jaxb.sample;
    
    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlElement;
    import javax.xml.bind.annotation.XmlRootElement;
    import javax.xml.bind.annotation.XmlType;
    
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {
        "jaxbNestedConfig"
    })
    @XmlRootElement(name = "jaxb-config")
    public class JaxbConfig {
    
        @XmlElement(required = true)
        protected JaxbConfig.JaxbNestedConfig jaxbNestedConfig;
    
        public JaxbConfig.JaxbNestedConfig getJaxbNestedConfig() {
            return jaxbNestedConfig;
        }
    
        public void setJaxbNestedConfig(JaxbConfig.JaxbNestedConfig value) {
            this.jaxbNestedConfig = value;
        }
    
        @XmlAccessorType(XmlAccessType.FIELD)
        @XmlType(name = "", propOrder = {
            "value"
        })
        public static class JaxbNestedConfig {
    
            @XmlElement(required = true)
            protected String value;
    
            public String getValue() {
                return value;
            }
    
            public void setValue(String value) {
                this.value = value;
            }
        }
    }
    

    修正例
    package jp.co.intra_mart.jaxb.sample;
    
    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlElement;
    import javax.xml.bind.annotation.XmlRootElement;
    import javax.xml.bind.annotation.XmlType;
    
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {
        "jaxbNestedConfig"
    }, factoryClass = ObjectFactory.class , factoryMethod = "createJaxbConfig")
    @XmlRootElement(name = "jaxb-config")
    public class JaxbConfig {
    
        @XmlElement(required = true)
        protected JaxbConfig.JaxbNestedConfig jaxbNestedConfig;
    
        public JaxbConfig.JaxbNestedConfig getJaxbNestedConfig() {
            return jaxbNestedConfig;
        }
    
        public void setJaxbNestedConfig(JaxbConfig.JaxbNestedConfig value) {
            this.jaxbNestedConfig = value;
        }
    
        @XmlAccessorType(XmlAccessType.FIELD)
        @XmlType(name = "", propOrder = {
            "value"
        }, factoryClass = ObjectFactory.class , factoryMethod = "createJaxbConfigJaxbNestedConfig")
        public static class JaxbNestedConfig {
    
            @XmlElement(required = true)
            protected String value;
    
            public String getValue() {
                return value;
            }
    
            public void setValue(String value) {
                this.value = value;
            }
        }
    }