Written by

Developer Support Engineer at InterSystems
Question Sam Duncan · Jul 12, 2023

Is there a good existing way to export all derived classes of a given class?

It can sometimes be useful to list or export all of the subclasses that are derived, directly or indirectly, from a given class. In Studio, the Class -> Derived Classes menu option will show such a list, but I'm not aware of a built-in API for programmatically exporting their source code.

Yesterday I wrote some code for exporting derived classes, and I'm thinking about cleaning it up and putting it on Open Exchange. But if there's a simple way to do this that someone has already figured out, I'd be happy to know about that (and help others find that solution) rather than reinventing the wheel. So:

  1. Have you ever wanted to export all of the subclasses derived from a particular class?
  2. If so, what solution did you come up with? Were you happy with it?

Comments

Eduard Lebedyuk · Jul 12, 2023

I usually export the entire package, but if you want subclasses run this query:

SELECTNameFROM %Dictionary.ClassDefinitionQuery_SubclassOf('%Persistent')

And then call $system.OBJ.ExportODL on every result.

0
Brett Saviano · Jul 13, 2023

@Samuel.DuncanHere's a simple method to export subclasses. It exports all of the classes in a single XML file and prints that to the console. You can easily modify that behavior by changing the $SYSTEM.OBJ.Export() line to whatever export strategy you want.

ClassMethod ExportSubclasses(pSuper As%String) As%Status
{
  #Dim tSC As%Status = $$$OK#Dim tEx As%Exception.AbstractException#Dim tPc As%ProcedureContext#Dim tRs As%SQL.ClassQueryResultSetTry {
    #; Build a subscripted array of subclassesSet tStmt = ##class(%SQL.Statement).%New()
    Set tSC = tStmt.%PrepareClassQuery("%Dictionary.ClassDefinitionQuery","SubclassOf")
    If$$$ISERR(tSC) QuitSet tPc = tStmt.%Execute(pSuper)
    If tPc.%SQLCODE < 0 {
      Throw##class(%Exception.SQL).CreateFromSQLCODE(tPc.%SQLCODE,tPc.%Message)
    }
    Set tRs = tPc.%NextResult()
    While tRs.%Next(.tSC) {
      Set tSubclasses(tRs.%GetData(1)_".CLS") = ""
    }
    If$$$ISOK(tSC), $DATA(tSubclasses) = 10 {
      #; Export the subclassesSet tSC = $SYSTEM.OBJ.Export(.tSubclasses,,"/nodisplay")
    }
  } Catch tEx {
    Set tSC = tEx.AsStatus()
  }
  Quit tSC
}
0
Sam Duncan  Jul 14, 2023 to Brett Saviano

Thanks, Brett! That seems to work, and is much more concise than what I had come up with.

0
Alex Woodhead · Jul 17, 2023
set basename="Test.Sub.Base"
set file="c:\temp\subclasses.xml"

// Get list of compiled sub-classes
do $SYSTEM.OBJ.GetDependencies(basename,.out,"/subclasses=1")
// If you didn't want the base class
kill out(basename)

// Write the classes to terminal
zwrite out

// Suffix for export
set next="" for {set next=$Order(out(next)) quit:next=""  set toExport(next_".CLS")=""}
// Fire in the hole !!
do $SYSTEM.OBJ.Export(.toExport,file,"/diffexport")

// to display different qualifier flags and values used by various OBJ methods ( /diffexport ):
do $SYSTEM.OBJ.ShowQualifiers()
0