WebObjects/EOF/使用 EOF/EOGenerator
如果您曾經使用過 EOModeler 的 Java 原始碼生成器,您就會知道,當您對模型物件進行更改並必須在以後合併更改時,這會多麼令人頭疼。解決此問題的一種方法是使用 EOGenerator,這是由 Rubicode Software 開發的應用程式,它使用 Generation Gap 模式從您的 EOModels 建立您的 Java 檔案。EOGenerator 為每個實體生成兩個 Java 檔案,而不是一個。以 Person 實體為例。第一個 Java 檔案是 _Person.java,其中包含所有自動生成的程式碼。第二個 Java 檔案是 Person.java,Person 擴充套件了 _Person。第二個檔案是您放置所有自定義程式碼的地方。每當您的模型更改時,只有您的 _Xxx.java 檔案會被更新,而您的自定義程式碼不會被更改。此外,EOGenerator 允許為您的檔案建立廣泛的自定義模板,這提供了將便利方法放置在您的 _Xxx.java 檔案中的能力。
與 EOModeler 的預設 Java 檔案生成以及與 FileMerge 的合併相比,使用 EOGenerator 具有若干優勢。
- EOGenerator 使用 Generation Gap 模式,該模式提供了自動生成程式碼與自定義程式碼之間的更清晰的分隔,而無需處理任何合併。FileMerge 存在一些邊界情況,會導致您處理令人討厭的衝突。
- EOGenerator 使用 MiscMerge 語言作為其模板。這使您能夠使用廣泛的自定義擴充套件核心模板(請參閱下面的 EOGenerator 模組部分),從而更好地支援您自己的自定義開發過程和工作流程。
- 正如 David LaBer 所說,“所有酷炫的人都使用它——而且我們都知道,看起來很酷是*最*重要的標準”。
Kieran Kelleher 在他的部落格上寫了一篇關於 EOGenerator 簡介 的文章。
實際上,使用它非常簡單。快速入門是
- 從 Rubicode 網站下載並解壓縮 EOGenerator
- 執行以下命令
eogenerator -model /path/to/model/YourModel.eomodeld -destination /path/to/source/folder -subclassDestination /path/to/source/folder -templatedir /path/to/EOGenerator/templates -java -packagedirs
瞧。EOGenerator 將為您生成您的 Java 檔案。讓我們分解您可以傳遞的命令
- -define-EOGenericRecord <class>,允許您指定 _Person 類 的超類。例如,如果您使用 Project Wonder,您將指定 -define-EOGenericRecord er.extensions.ERXGenericRecord
- -destination <path>,將生成 _Person.java 風格的 java 檔案的資料夾(不可編輯檔案)
- -java,生成 java 檔案
- -javaTemplate <filename>,模板目錄 (_Person) 內要使用的 Java 模板的名稱
- -model <path>,傳入要為其生成 Java 檔案的 .eomodeld 的路徑。您實際上可以在命令列上包含多個 -model 命令
- -packagedirs,為在 Java 檔案中定義的任何包語句生成包目錄(如果您沒有在實體上指定包名稱,則不需要。順便說一句,您應該在實體上指定包 :) )
- -refmodel <path>,傳入生成 Java 檔案所需的 .eomodeld 的路徑,但不會為其實際生成 Java 檔案。例如,您應該為任何原型或任何您依賴的其他框架中的模型 -refmodel
- -subclassDestination <path>,將生成 Person.java 風格的 java 檔案的資料夾(可編輯檔案)
- -subclassJavaTemplate <filename>,模板目錄 (Person) 內要使用的 Java 子類模板的名稱
- -templatedir <path>,包含 EOGenerator 模板的資料夾的路徑
- -verbose,開啟詳細輸出
允許在一對一關係上設定空值(並將其轉換為刪除)。注意,這也被包含在 Jonathan Rentzsch 的模板中。
public void save<$ToOneRelationship.name.initialCapitalString$>(<$ToOneRelationship.destinationEntity.referenceJavaClassName$> value)
{
if (value == null)
{
<$ToOneRelationship.destinationEntity.referenceJavaClassName$> object = <$ToOneRelationship.name$>();
if (object != null)
removeObjectFromBothSidesOfRelationshipWithKey(object, "<$ToOneRelationship.name$>");
}
else
{
addObjectToBothSidesOfRelationshipWithKey(value, "<$ToOneRelationship.name$>");
}
}
返回當前 EO 與 EO 的最後一個提交版本之間的更改列表
public NSDictionary changedProperties() {
NSDictionary commitedValues = editingContext().committedSnapshotForObject(this);
return changesFromSnapshot(commitedValues);
}
Jonathan Rentzsch 提供了他的基本 EOGenerator 模板,這些模板是必不可少的
http://rentzsch.com/share/eogenerator52templates.zip
所有屬性和關係的常量。這允許在 addObjecttoBothSidesOfRelationshipWithKey(myObject, Person.TO_MANY_Children) 這樣的情況下進行編譯時錯誤檢查
<$foreach attribute classAttributes.@reversedArray do$> public static final String ATTRIBUTE_<$attribute.name$> = "<$attribute.name$>";<$endforeach do$>
<$foreach ToOneRelationship classToOneRelationships.@reversedArray do$> public static final String TO_ONE_<$ToOneRelationship.name$> = "<$ToOneRelationship.name$>";<$endforeach do$>
<$foreach ToManyRelationship classToManyRelationships.@reversedArray do$> public static final String TO_MANY_<$ToManyRelationship.name$> = "<$ToManyRelationship.name$>";<$endforeach do$>
我們還大量使用實體和屬性級別的使用者資訊字典。允許生成自定義方法等等。一個例子是儲存在資料庫中的布林值,其值為“true”和“false”。
<$if attribute.userInfo.usage == booleanFlag $> // boolean accessors
public void <$attribute.userInfo.setterName$>(boolean newBoolean) {
set<$attribute.name.initialCapitalString$>(newBoolean ? "true" : "false");
}
public boolean <$attribute.userInfo.getterName$>() {
return "true".equals(<$attribute.name$>()) ? true : false;
}
// validation
public String validate<$attribute.name.initialCapitalString$>(String newValue) {
if ( newValue == null ) {
return "false";
} else if ( !newValue.equals("true") && !newValue.equals("false") ) {
String errorMessage = MessageHandler.format("INVALID_BOOLEAN_FLAG <$classNameWithoutPackage$>.<$attribute.name$>", null);
throw new NSValidation.ValidationException(errorMessage);
}
return newValue;
}
<$endif$>
新增一個表示實體名稱的常量,以便您可以在獲取中引用 Person.ENTITY_NAME 而不是字串(允許在 Eclipse 中進行重構支援)
public static final String ENTITY_NAME = "<$name$>";
在您的 EO (Person createPerson(...) ) 中新增一個靜態工廠方法,該方法向您顯示為您的實體配置了哪些必需屬性和關係(嘗試提供一個替換的“建構函式”,因為 EO 建構函式是空的)
public static <$classNameWithoutPackage$> create<$classNameWithoutPackage$>(EOEditingContext _editingContext<$foreach Attribute classAttributes.@sortedNameArray do$><$if !Attribute.allowsNull$>, <$Attribute.javaValueClassName$> _<$Attribute.name$><$endif$><$endforeach do$><$foreach ToOneRelationship classToOneRelationships.@sortedNameArray do$><$if ToOneRelationship.isMandatory$>, <$ToOneRelationship.destinationEntity.referenceJavaClassName$> _<$ToOneRelationship.name$><$endif$><$endforeach do$>) {
<$classNameWithoutPackage$> eoObject = (<$classNameWithoutPackage$>)EOUtilities.createAndInsertInstance(_editingContext, <$GEN_PREFIX$><$classNameWithoutPackage$>.ENTITY_NAME);<$foreach Attribute classAttributes.@sortedNameArray do$><$if !Attribute.allowsNull$>
eoObject.set<$Attribute.name.initialCapitalString$>(_<$Attribute.name$>);<$endif$><$endforeach do$><$foreach ToOneRelationship classToOneRelationships.@sortedNameArray do$><$if ToOneRelationship.isMandatory$>
eoObject.set<$ToOneRelationship.name.initialCapitalString$>Relationship(_<$ToOneRelationship.name$>);<$endif$><$endforeach do$>
return eoObject;
}
這是一個稍微花哨一點(即更難看)的版本,它還處理超類必需屬性和欄位(一級)。它跳過任何在您的子類的限制限定符中引用的屬性(因為您可能會在 awakeFromInsertion 中設定它)
public static <$classNameWithoutPackage$> create<$classNameWithoutPackage$>(EOEditingContext editingContext<$foreach Attribute classAttributes.@sortedNameArray do$><$if !Attribute.allowsNull$>, <$Attribute.javaValueClassName$> <$Attribute.name$><$endif$><$endforeach do$><$foreach Attribute parentEntity.classAttributes.@sortedNameArray do$><$if !Attribute.allowsNull$><$set RestrictingQualifierKey = false$><$foreach QualifierKey restrictingQualifier.allQualifierKeys do$><$if Attribute.name = QualifierKey$><$set RestrictingQualifierKey = true$><$endif$><$endforeach do$><$if RestrictingQualifierKey = false$>, <$Attribute.javaValueClassName$> <$Attribute.name$><$endif$><$endif$><$endforeach do$><$foreach ToOneRelationship classToOneRelationships.@sortedNameArray do$><$if ToOneRelationship.isMandatory$>, <$ToOneRelationship.destinationEntity.referenceJavaClassName$> <$ToOneRelationship.name$><$endif$><$endforeach do$><$foreach ToOneRelationship parentEntity.classToOneRelationships.@sortedNameArray do$><$if ToOneRelationship.isMandatory$>, <$ToOneRelationship.destinationEntity.referenceJavaClassName$> <$ToOneRelationship.name$><$endif$><$endforeach do$>) {
<$classNameWithoutPackage$> eoObject = (<$classNameWithoutPackage$>)EOUtilities.createAndInsertInstance(editingContext, <$GEN_PREFIX$><$classNameWithoutPackage$>.ENTITY_NAME);<$foreach Attribute classAttributes.@sortedNameArray do$><$if !Attribute.allowsNull$>
eoObject.set<$Attribute.name.initialCapitalString$>(<$Attribute.name$>);<$endif$><$endforeach do$><$foreach ToOneRelationship classToOneRelationships.@sortedNameArray do$><$if ToOneRelationship.isMandatory$>
eoObject.set<$ToOneRelationship.name.initialCapitalString$>Relationship(<$ToOneRelationship.name$>);<$endif$><$endforeach do$><$foreach Attribute parentEntity.classAttributes.@sortedNameArray do$><$if !Attribute.allowsNull$><$set RestrictingQualifierKey = false$><$foreach QualifierKey restrictingQualifier.allQualifierKeys do$><$if Attribute.name = QualifierKey$><$set RestrictingQualifierKey = true$><$endif$><$endforeach do$><$if RestrictingQualifierKey = false$>
eoObject.set<$Attribute.name.initialCapitalString$>(<$Attribute.name$>);<$endif$><$endif$><$endforeach do$><$foreach ToOneRelationship parentEntity.classToOneRelationships.@sortedNameArray do$><$if ToOneRelationship.isMandatory$>
eoObject.set<$ToOneRelationship.name.initialCapitalString$>Relationship(<$ToOneRelationship.name$>);<$endif$><$endforeach do$>
return eoObject;
}
新增一堆便利獲取方法(fetchAllPersons、fetchRequiredPerson 和其他變體)。它對複數化不智慧,因此它只是在實體名稱的末尾加上一個“s”
public static NSArray fetchAll<$classNameWithoutPackage$>s(EOEditingContext _editingContext) {
return <$GEN_PREFIX$><$classNameWithoutPackage$>.fetchAll<$classNameWithoutPackage$>s(_editingContext, null);
}
public static NSArray fetchAll<$classNameWithoutPackage$>s(EOEditingContext _editingContext, NSArray _sortOrderings) {
return <$GEN_PREFIX$><$classNameWithoutPackage$>.fetch<$classNameWithoutPackage$>s(_editingContext, null, _sortOrderings);
}
public static NSArray fetch<$classNameWithoutPackage$>s(EOEditingContext _editingContext, EOQualifier _qualifier, NSArray _sortOrderings) {
EOFetchSpecification fetchSpec = new EOFetchSpecification(<$GEN_PREFIX$><$classNameWithoutPackage$>.ENTITY_NAME, _qualifier, _sortOrderings);
fetchSpec.setIsDeep(true);
NSArray eoObjects = _editingContext.objectsWithFetchSpecification(fetchSpec);
return eoObjects;
}
public static <$classNameWithoutPackage$> fetch<$classNameWithoutPackage$>(EOEditingContext _editingContext, String _keyName, Object _value) {
return <$GEN_PREFIX$><$classNameWithoutPackage$>.fetch<$classNameWithoutPackage$>(_editingContext, new EOKeyValueQualifier(_keyName, EOQualifier.QualifierOperatorEqual, _value));
}
public static <$classNameWithoutPackage$> fetch<$classNameWithoutPackage$>(EOEditingContext _editingContext, EOQualifier _qualifier) {
NSArray eoObjects = <$GEN_PREFIX$><$classNameWithoutPackage$>.fetch<$classNameWithoutPackage$>s(_editingContext, _qualifier, null);
<$classNameWithoutPackage$> eoObject;
int count = eoObjects.count();
if (count == 0) {
eoObject = null;
}
else if (count == 1) {
eoObject = (<$classNameWithoutPackage$>)eoObjects.objectAtIndex(0);
}
else {
throw new IllegalStateException("There was more than one <$classNameWithoutPackage$> that matched the qualifier '" + _qualifier + "'.");
}
return eoObject;
}
public static <$classNameWithoutPackage$> fetchRequired<$classNameWithoutPackage$>(EOEditingContext _editingContext, String _keyName, Object _value) {
return <$GEN_PREFIX$><$classNameWithoutPackage$>.fetchRequired<$classNameWithoutPackage$>(_editingContext, new EOKeyValueQualifier(_keyName, EOQualifier.QualifierOperatorEqual, _value));
}
public static <$classNameWithoutPackage$> fetchRequired<$classNameWithoutPackage$>(EOEditingContext _editingContext, EOQualifier _qualifier) {
<$classNameWithoutPackage$> eoObject = <$GEN_PREFIX$><$classNameWithoutPackage$>.fetch<$classNameWithoutPackage$>(_editingContext, _qualifier);
if (eoObject == null) {
throw new NoSuchElementException("There was no <$classNameWithoutPackage$> that matched the qualifier '" + _qualifier + "'.");
}
return eoObject;
}
新增用於獲取 EO 的本地例項的方法。如果您對可能為空的 EO 有引用,靜態方法會很方便(它首先執行空值檢查)
public <$classNameWithoutPackage$> localInstanceOf<$classNameWithoutPackage$>(EOEditingContext _editingContext) {
return (<$classNameWithoutPackage$>)EOUtilities.localInstanceOfObject(_editingContext, this);
}
public static <$classNameWithoutPackage$> localInstanceOf<$classNameWithoutPackage$>(EOEditingContext _editingContext, <$classNameWithoutPackage$> _eo) {
return (_eo == null) ? null : (<$classNameWithoutPackage$>)EOUtilities.localInstanceOfObject(_editingContext, _eo);
}
如果您曾經想在您的 EO 上限定一個 toMany 關係,但有時您想使用獲取規範獲取它們,有時您想在記憶體中進行過濾,您可以使用以下方法
<$if !ToManyRelationship.inverseRelationship$>
public NSArray <$ToManyRelationship.name$>(EOQualifier qualifier) {
return <$ToManyRelationship.name$>(qualifier, null);
}
<$endif$>
<$if ToManyRelationship.inverseRelationship$>
public NSArray <$ToManyRelationship.name$>(EOQualifier qualifier) {
return <$ToManyRelationship.name$>(qualifier, null, false);
}
public NSArray <$ToManyRelationship.name$>(EOQualifier qualifier, boolean fetch) {
return <$ToManyRelationship.name$>(qualifier, null, fetch);
}
<$endif$>
public NSArray <$ToManyRelationship.name$>(EOQualifier qualifier, NSArray sortOrderings<$if ToManyRelationship.inverseRelationship$>, boolean fetch<$endif$>) {
NSArray results;
<$if ToManyRelationship.inverseRelationship$>
if (fetch) {
EOQualifier fullQualifier;
EOQualifier inverseQualifier = new EOKeyValueQualifier(<$ToManyRelationship.destination.className$>.<$ToManyRelationship.inverseRelationship.name.uppercaseUnderbarString$>_KEY, EOQualifier.QualifierOperatorEqual, this);
if (qualifier == null) {
fullQualifier = inverseQualifier;
}
else {
NSMutableArray qualifiers = new NSMutableArray();
qualifiers.addObject(qualifier);
qualifiers.addObject(inverseQualifier);
fullQualifier = new EOAndQualifier(qualifiers);
}
results = <$ToManyRelationship.destination.className$>.fetch<$ToManyRelationship.destination.name$>s(editingContext(), fullQualifier, sortOrderings);
}
else {
<$endif$>
results = <$ToManyRelationship.name$>();
if (qualifier != null) {
results = EOQualifier.filteredArrayWithQualifier(results, qualifier);
}
if (sortOrderings != null) {
results = EOSortOrdering.sortedArrayUsingKeyOrderArray(results, sortOrderings);
}
<$if ToManyRelationship.inverseRelationship$>
}
<$endif$>
return results;
}
我想分享今天學到的一點很棒的知識。如果您使用的是 Java 1.5,您可以在 _EO 基礎類的模板中新增 @SuppressWarnings("all"),並消除惱人的編譯器訊息(通常是不必要的匯入語句)。
@SuppressWarnings("all")
public class _Invoice extends ERXGenericRecord {
}
在您的 EOGenerator 模板中建立 awakeFromInsertion() 和 awakeFromFetch() 作為方法存根,該方法存根僅呼叫 super() 並有一個“在此處初始化您的物件...”的註釋。您只需要在那個地方放入程式碼,並且不可能忘記呼叫 super()。以下是一個示例
/**
* Initialization of the instance while inserting it into an editing context
*/
public void awakeFromInsertion (EOEditingContext editingContext) {
super.awakeFromInsertion (editingContext);
// initialize your object here
}
這是來自我的 JavaSubclassSourceTemplate.eotemplate 的