ApexでgetDescribeをもっと簡単に使いたい。

getDescribeってたまに使うのですが、コードが長くなってしまうので短くできないかとまとめてみました。

###使うときはこんな感じで
```java
String AccountNameLabel = Describer.getFieldLabel('Account', 'name');
```

###こっちをコピーして
```java:Describer.apxc
public class Describer {
    
    public class DescriberException extends Exception {}
    
    // オブジェクトタイプから、そのオブジェクトタイプが有効であるか確認する。
    public static Boolean isValidSObjectType(String objType){ 
        Boolean ret = false;
        if(!isNullOrEmpty(objType)){
            ret = Schema.getGlobalDescribe().containsKey(objType);
        }
        o('Describer.isValidSObjectType: object type \'' + objType + '\' is valid? ' + ret);
        return ret;
    }
    
    // オブジェクトタイプとフィールド名から、そのフィールドがオブジェクトで有効なフィールドであるか確認する。
    public static Boolean isValidFieldName(String objType, String fieldName){
        Boolean ret = false;
        if(isValidSObjectType(objType) && !isNullOrEmpty(fieldName)){
            ret = Schema.getGlobalDescribe().get(objType).getDescribe().fields.getMap().containsKey(fieldName);
        }   
        o('Describer.isValidFieldName: field \'' + fieldName + '\' for object type \'' + objType + '\' is valid? ' + ret);
        return ret;
    }
    
    // オブジェクトタイプとフィールド名からラベル名を取得する。
    public static String getFieldLabel(String objType, String fieldName){
        return getDescribeFieldResult(objType, fieldName).getLabel();
    }
    
    // オブジェクトタイプとフィールド名からフィールドタイプを取得する。
    public static Schema.DisplayType getFieldType(String objType, String fieldName){
        return getDescribeFieldResult(objType, fieldName).getType();
    }
    
    // オブジェクトタイプとフィールド名から関連名を取得する。
    public static String getRelationshipName(String objType, String fieldName){
        Schema.DescribeFieldResult dfr = getDescribeFieldResult(objType, fieldName);
        if(dfr.getType() != Schema.DisplayType.REFERENCE) throw new DescriberException('\''+fieldName + '\' of \'' + objType + '.\' is not a reference type.');
        return dfr.getRelationshipName();
    }
    
    // オブジェクトタイプとフィールド名から、フィールドが参照型の際に参照先のオブジェクトタイプ(複数)を取得する。
    public static Set<String> getReferenceTo(String objType, String fieldName){
        Schema.DescribeFieldResult dfr = getDescribeFieldResult(objType, fieldName);
        if(dfr.getType() != Schema.DisplayType.REFERENCE) throw new DescriberException('\''+fieldName + '\' of \'' + objType + '.\' is not a reference type.');
        
        Set<String> ret = new Set<String>();
        List<Schema.SObjectType> objTypeList = dfr.getReferenceTo();
        for(Schema.SObjectType t : objTypeList){
            ret.add(t.getDescribe().getName());
        }
        return ret;
    }
    
    // オブジェクトタイプと関連名から、関連先のオブジェクトタイプを取得する。
    public static String getChildObjectType(String objType, String relationshipName){
        if(!isValidSObjectType(objType)) throw new DescriberException('\''+objType + '\' is not a valid sObject type.');
        if(!isValidChildRelationshipName(objType, relationshipName)) throw new DescriberException('\'' + relationshipName + '\' is not a valid child relationship name for sObject \'' + objType + '.\'');
        
        String ret = null;             
        for(Schema.ChildRelationship childRelName : Schema.getGlobalDescribe().get(objType.trim()).getDescribe().getChildRelationships()){
            if(!isNullOrEmpty(childRelName.getRelationshipName()) && childRelName.getrelationshipname().toLowerCase() == relationshipName.toLowerCase()){ 
                ret = childRelName.getChildSObject().getDescribe().getName();
                break;
            }
        }
        return ret;
    }
    
    // レコードIdから、オブジェクトタイプを取得する。
    public static String getObjectType(String recordId){
        if(!isValidRecordId(recordId)) throw new DescriberException('\'' + recordId + '\' is not a valid record ID.');
        Id recordIdFromString = recordId;
        return recordIdFromString.getSObjectType().getDescribe().getName();
    }
    
    // レコードIdが、正しいレコードIdかを確認する
    public static Boolean isValidRecordId(String recordId){
        Boolean ret = false;
        ret = !isNullOrEmpty(recordId) && recordId InstanceOf ID ;
        o('Describer.isValidRecordId: record Id \'' + recordId + '\' is valid? ' + ret);
        return ret;
    }
    
    // オブジェクトタイプと関連名から、その関連名がオブジェクトで有効であるか確認する。
    public static Boolean isValidChildRelationshipName(String objType, String relationshipName){
        Boolean ret = false;
        if(isValidSObjectType(objType) && !isNullOrEmpty(relationshipName)){    
            for(Schema.ChildRelationship childRelName : Schema.getGlobalDescribe().get(objType).getDescribe().getChildRelationships()){
                if(!isNullOrEmpty(childRelName.getRelationshipName()) && childRelName.getRelationshipName().toLowerCase() == relationshipName.toLowerCase()){ 
                    ret = true;
                    break;
                }
            }
        }
        o('Describer.isValidRelationshipName: relationship name \'' + relationshipName + '\' for object type \'' + objType + '\' is valid? ' + ret);
        return ret;
    }
    
    // オブジェクト名とフィールド名から sObjectField を取得する。
    @testVisible
    private static Schema.DescribeFieldResult getDescribeFieldResult(String objType, String fieldName){
        if(!isValidSObjectType(objType))          throw new DescriberException('\''+objType + '\' is not a valid sObject type.');
        if(!isValidFieldName(objType, fieldName)) throw new DescriberException('\''+fieldName + '\' is not a valid field name for sObject \'' + objType + '.\'');
        return Schema.getGlobalDescribe().get(objType).getDescribe().fields.getMap().get(fieldName).getDescribe();
    }
    
    // デバッグ用
    // よくわからない時はとりあえず、コメントを消してログに出してみる。ランタイムコストはヤバイ。
    private static void o(Object o){
        //System.debug(JSON.serializePretty(o));
    }
    
    @testVisible
    private static Boolean isNullOrEmpty(Object o){
        return o == null || String.valueOf(o) == '';
    }
}
```