http://www.perlmonks.org?node_id=305381

Why should you use Perl? Wheneven others ask this question, I always say, there is no way you can develop this faster in other languages than do it in Perl. There must be lots of other valid answers, but I see as the best answer that everyone can easily accept, if you do not want run into lengthy and most likely fruitless arguing.

Now here is one example. I have been working on the design of a three-tier enterprise web application for half year already (the design is based on J2EE), and yesterday I got a chance to do a little bit coding. Right the way, I realized what a waste of time it is to code all those DCO’s, so I decided to code a tool to generate those DCO’s. Obviously I did it in Perl, and it only took me half hour. When I showed the results to others, they were totally surprised, as there was one guy did this same thing in Java to help himself, and it took him 2 –3 days. I guess he did it on and off, but still Perl takes much less developing time.

I share the code here with everyone. There are obviously spaces for improvement, for example: I convert all Oracle NUMBER type to java long/Long, but probably I should convert it to either long or int base on the length, but that is not a big concern to me at this moment.

A little bit explanation on the naming cionvention, so you know why certain lines are there. All Oracle tables and columns named like FOO_BAR, and when they get converted to java, they would be named fooBar, and methods would be named setFooBar, getFooBar.

A big saving of time, both what the tool can provide, and the development of the tool itself. This is also a good opportunity to educate people around you, with very solid result.

The input file to the program is got from Oracle desc, which gives you a table-like description of all columns in a table. The first column is column name, second says whether null value is allowed, and the third one gives the data type. There are more columns descibing things like length, precision, default value etc., which I don’t use at this point.

use Data::Dumper; use strict; use warnings; my $def = {}; my $java_var = {}; my $table = $ARGV[0]; open(DEF, "<", $table . ".def"); while (my $line = <DEF>) { my @comp = split(/,/, $line); my $col = join("", map {ucfirst(lc())} split(/_/, shift @comp)); $def->{$col} = \@comp; } close(DEF); $table = join("", map {ucfirst(lc())} split(/_/, $table)); print $table; open(JAVA, ">", $table . "DCO.java"); print JAVA "package com.owfg.po.model.dco;\n\n"; print JAVA "import java.io.Serializable;\n"; print JAVA "import java.sql.Date;\n\n"; print JAVA "public class $table implements Serializable {\n\n"; foreach (sort(keys(%$def))) { $java_var->{lcfirst($_)} = java_type($def, $_); print JAVA variable_declaration($def, $_), "\n"; } print JAVA "\n"; print JAVA new($java_var); foreach (sort(keys(%$java_var))) { print JAVA get($java_var, $_); } foreach (sort(keys(%$java_var))) { print JAVA set($java_var, $_); } print JAVA "}"; close(JAVA); sub variable_declaration { my ($def, $var) = @_; return sprintf("\tprivate %s %s; //%s %s", java_type($def, $var), +lcfirst($var), oracle_type($def, $var), null_allowed($def, $var)); } sub java_type { my ($def, $var) = @_; if ($def->{$var}->[1] eq "NUMBER") { if ($def->{$var}->[0] eq "N") { return "long"; } else { return "Long"; } } elsif ($def->{$var}->[1] eq "DATE") { return "Date"; } elsif ($def->{$var}->[1] eq "VARCHAR2") { return "String"; } elsif ($def->{$var}->[1] eq "FLOAT") { return "float"; } else { print $def->{$var}->[1]; return undef; } } sub oracle_type { my ($def, $var) = @_; if ($def->{$var}->[1] eq "DATE") { return "DATE"; } else { return sprintf("%s(%d)", $def->{$var}->[1], $def->{$var}->[2]) +; } } sub null_allowed { my ($def, $var) = @_; if ($def->{$var}->[0] eq "N") { return "NOT NULL"; } else { return "NULL"; } } sub set { my ($java_var, $var) = @_; return sprintf("\tpublic void set%s(%s %s) {\n\t\tthis.%s = %s;\n\ +t}\n\n", ucfirst($var), $java_var->{$var}, $var, $var, $var); } sub get { my ($java_var, $var) = @_; return sprintf("\tpublic %s get%s() {\n\t\treturn %s;\n\t}\n\n", $ +java_var->{$var}, ucfirst($var), $var); } sub new { my $java_var = shift; my $ret = "\tpublic ordrcostDCO() {\n"; foreach (sort(keys(%$java_var))) { if ($java_var->{$_} eq "long") { $ret .= "\t\t$_ = 0;\n"; } elsif ($java_var->{$_} eq "Long") { $ret .= "\t\t$_ = new Long(0);\n"; } elsif ($java_var->{$_} eq "float") { $ret .= "\t\t$_ = .0;\n"; } elsif ($java_var->{$_} eq "String") { $ret .= "\t\t$_ = \"\";\n"; } elsif ($java_var->{$_} eq "Date") { $ret .= "\t\t$_ = new Date(new java.util.Date().gtTime())) +;\n"; } } $ret .= "\t}\n\n"; return $ret; }
Sample input:
ORDR_COST_NUMB,N,NUMBER,10,10,0, ORGU_NUMB_ORDR,Y,NUMBER,10,10,0, ORDR_NUMB_ORDR,Y,NUMBER,10,10,0, ORGU_NUMB_OLIN,Y,NUMBER,10,10,0, ORDR_NUMB_OLIN,Y,NUMBER,10,10,0, OLIN_NUMB,Y,NUMBER,10,10,0, ORGU_NUMB_SHPT,Y,NUMBER,10,10,0, SHPT_NUMB,Y,NUMBER,10,10,0, BITM_NUMB,Y,NUMBER,10,10,0, COST_TYPE_CODE,N,VARCHAR2,4,,, COST_TYPE_CODE_AMC,Y,VARCHAR2,4,,, DEAL_NUMB,Y,NUMBER,10,10,0, PYMT_MTHD_CODE,N,VARCHAR2,6,,, ORGU_NUMB_SUPP,Y,NUMBER,10,10,0, UOM_CODE,Y,VARCHAR2,4,,, UOM_CODE_DIST_BSS,Y,VARCHAR2,4,,, UOM_CODE_WGHT,Y,VARCHAR2,4,,, ORDR_COST_LCKD_IND,N,VARCHAR2,1,,, COST_ITEM_MLTP,N,NUMBER,10,10,0, CSTP_AMNT,N,FLOAT,22,126,, CSTP_AMNT_WGHT,N,FLOAT,22,126,, DEAL_QUAN,Y,FLOAT,22,126,, COST_TYPE_CODE_NT1,Y,VARCHAR2,4,,, CSTP_AMNT_NT1,Y,FLOAT,22,126,, COST_TYPE_CODE_NT2,Y,VARCHAR2,4,,, CSTP_AMNT_NT2,Y,FLOAT,22,126,, COST_TYPE_CODE_NT3,Y,VARCHAR2,4,,, CSTP_AMNT_NT3,Y,FLOAT,22,126,, CNCY_NUMB_CSTP,N,NUMBER,10,10,0, CNCY_NUMB_NT1,N,NUMBER,10,10,0, CNCY_NUMB_NT2,N,NUMBER,10,10,0, CNCY_NUMB_NT3,N,NUMBER,10,10,0, CNCY_NUMB,N,NUMBER,10,10,0, CNCY_NUMB_WGHT,N,NUMBER,10,10,0, X_CNT,N,NUMBER,10,10,0,
Sample output:
package com.owfg.po.model.dco; import java.io.Serializable; import java.sql.Date; public class OrdrCost implements Serializable { private Long bitmNumb; //NUMBER(10) NULL private long cncyNumb; //NUMBER(10) NOT NULL private long cncyNumbCstp; //NUMBER(10) NOT NULL private long cncyNumbNt1; //NUMBER(10) NOT NULL private long cncyNumbNt2; //NUMBER(10) NOT NULL private long cncyNumbNt3; //NUMBER(10) NOT NULL private long cncyNumbWght; //NUMBER(10) NOT NULL private long costItemMltp; //NUMBER(10) NOT NULL private String costTypeCode; //VARCHAR2(4) NOT NULL private String costTypeCodeAmc; //VARCHAR2(4) NULL private String costTypeCodeNt1; //VARCHAR2(4) NULL private String costTypeCodeNt2; //VARCHAR2(4) NULL private String costTypeCodeNt3; //VARCHAR2(4) NULL private float cstpAmnt; //FLOAT(22) NOT NULL private float cstpAmntNt1; //FLOAT(22) NULL private float cstpAmntNt2; //FLOAT(22) NULL private float cstpAmntNt3; //FLOAT(22) NULL private float cstpAmntWght; //FLOAT(22) NOT NULL private Long dealNumb; //NUMBER(10) NULL private float dealQuan; //FLOAT(22) NULL private Long olinNumb; //NUMBER(10) NULL private String ordrCostLckdInd; //VARCHAR2(1) NOT NULL private long ordrCostNumb; //NUMBER(10) NOT NULL private Long ordrNumbOlin; //NUMBER(10) NULL private Long ordrNumbOrdr; //NUMBER(10) NULL private Long orguNumbOlin; //NUMBER(10) NULL private Long orguNumbOrdr; //NUMBER(10) NULL private Long orguNumbShpt; //NUMBER(10) NULL private Long orguNumbSupp; //NUMBER(10) NULL private String pymtMthdCode; //VARCHAR2(6) NOT NULL private Long shptNumb; //NUMBER(10) NULL private String uomCode; //VARCHAR2(4) NULL private String uomCodeDistBss; //VARCHAR2(4) NULL private String uomCodeWght; //VARCHAR2(4) NULL private long xCnt; //NUMBER(10) NOT NULL public ordrcostDCO() { bitmNumb = new Long(0); cncyNumb = 0; cncyNumbCstp = 0; cncyNumbNt1 = 0; cncyNumbNt2 = 0; cncyNumbNt3 = 0; cncyNumbWght = 0; costItemMltp = 0; costTypeCode = ""; costTypeCodeAmc = ""; costTypeCodeNt1 = ""; costTypeCodeNt2 = ""; costTypeCodeNt3 = ""; cstpAmnt = .0; cstpAmntNt1 = .0; cstpAmntNt2 = .0; cstpAmntNt3 = .0; cstpAmntWght = .0; dealNumb = new Long(0); dealQuan = .0; olinNumb = new Long(0); ordrCostLckdInd = ""; ordrCostNumb = 0; ordrNumbOlin = new Long(0); ordrNumbOrdr = new Long(0); orguNumbOlin = new Long(0); orguNumbOrdr = new Long(0); orguNumbShpt = new Long(0); orguNumbSupp = new Long(0); pymtMthdCode = ""; shptNumb = new Long(0); uomCode = ""; uomCodeDistBss = ""; uomCodeWght = ""; xCnt = 0; } public Long getBitmNumb() { return bitmNumb; } public long getCncyNumb() { return cncyNumb; } public long getCncyNumbCstp() { return cncyNumbCstp; } public long getCncyNumbNt1() { return cncyNumbNt1; } public long getCncyNumbNt2() { return cncyNumbNt2; } public long getCncyNumbNt3() { return cncyNumbNt3; } public long getCncyNumbWght() { return cncyNumbWght; } public long getCostItemMltp() { return costItemMltp; } public String getCostTypeCode() { return costTypeCode; } public String getCostTypeCodeAmc() { return costTypeCodeAmc; } public String getCostTypeCodeNt1() { return costTypeCodeNt1; } public String getCostTypeCodeNt2() { return costTypeCodeNt2; } public String getCostTypeCodeNt3() { return costTypeCodeNt3; } public float getCstpAmnt() { return cstpAmnt; } public float getCstpAmntNt1() { return cstpAmntNt1; } public float getCstpAmntNt2() { return cstpAmntNt2; } public float getCstpAmntNt3() { return cstpAmntNt3; } public float getCstpAmntWght() { return cstpAmntWght; } public Long getDealNumb() { return dealNumb; } public float getDealQuan() { return dealQuan; } public Long getOlinNumb() { return olinNumb; } public String getOrdrCostLckdInd() { return ordrCostLckdInd; } public long getOrdrCostNumb() { return ordrCostNumb; } public Long getOrdrNumbOlin() { return ordrNumbOlin; } public Long getOrdrNumbOrdr() { return ordrNumbOrdr; } public Long getOrguNumbOlin() { return orguNumbOlin; } public Long getOrguNumbOrdr() { return orguNumbOrdr; } public Long getOrguNumbShpt() { return orguNumbShpt; } public Long getOrguNumbSupp() { return orguNumbSupp; } public String getPymtMthdCode() { return pymtMthdCode; } public Long getShptNumb() { return shptNumb; } public String getUomCode() { return uomCode; } public String getUomCodeDistBss() { return uomCodeDistBss; } public String getUomCodeWght() { return uomCodeWght; } public long getXCnt() { return xCnt; } public void setBitmNumb(Long bitmNumb) { this.bitmNumb = bitmNumb; } public void setCncyNumb(long cncyNumb) { this.cncyNumb = cncyNumb; } public void setCncyNumbCstp(long cncyNumbCstp) { this.cncyNumbCstp = cncyNumbCstp; } public void setCncyNumbNt1(long cncyNumbNt1) { this.cncyNumbNt1 = cncyNumbNt1; } public void setCncyNumbNt2(long cncyNumbNt2) { this.cncyNumbNt2 = cncyNumbNt2; } public void setCncyNumbNt3(long cncyNumbNt3) { this.cncyNumbNt3 = cncyNumbNt3; } public void setCncyNumbWght(long cncyNumbWght) { this.cncyNumbWght = cncyNumbWght; } public void setCostItemMltp(long costItemMltp) { this.costItemMltp = costItemMltp; } public void setCostTypeCode(String costTypeCode) { this.costTypeCode = costTypeCode; } public void setCostTypeCodeAmc(String costTypeCodeAmc) { this.costTypeCodeAmc = costTypeCodeAmc; } public void setCostTypeCodeNt1(String costTypeCodeNt1) { this.costTypeCodeNt1 = costTypeCodeNt1; } public void setCostTypeCodeNt2(String costTypeCodeNt2) { this.costTypeCodeNt2 = costTypeCodeNt2; } public void setCostTypeCodeNt3(String costTypeCodeNt3) { this.costTypeCodeNt3 = costTypeCodeNt3; } public void setCstpAmnt(float cstpAmnt) { this.cstpAmnt = cstpAmnt; } public void setCstpAmntNt1(float cstpAmntNt1) { this.cstpAmntNt1 = cstpAmntNt1; } public void setCstpAmntNt2(float cstpAmntNt2) { this.cstpAmntNt2 = cstpAmntNt2; } public void setCstpAmntNt3(float cstpAmntNt3) { this.cstpAmntNt3 = cstpAmntNt3; } public void setCstpAmntWght(float cstpAmntWght) { this.cstpAmntWght = cstpAmntWght; } public void setDealNumb(Long dealNumb) { this.dealNumb = dealNumb; } public void setDealQuan(float dealQuan) { this.dealQuan = dealQuan; } public void setOlinNumb(Long olinNumb) { this.olinNumb = olinNumb; } public void setOrdrCostLckdInd(String ordrCostLckdInd) { this.ordrCostLckdInd = ordrCostLckdInd; } public void setOrdrCostNumb(long ordrCostNumb) { this.ordrCostNumb = ordrCostNumb; } public void setOrdrNumbOlin(Long ordrNumbOlin) { this.ordrNumbOlin = ordrNumbOlin; } public void setOrdrNumbOrdr(Long ordrNumbOrdr) { this.ordrNumbOrdr = ordrNumbOrdr; } public void setOrguNumbOlin(Long orguNumbOlin) { this.orguNumbOlin = orguNumbOlin; } public void setOrguNumbOrdr(Long orguNumbOrdr) { this.orguNumbOrdr = orguNumbOrdr; } public void setOrguNumbShpt(Long orguNumbShpt) { this.orguNumbShpt = orguNumbShpt; } public void setOrguNumbSupp(Long orguNumbSupp) { this.orguNumbSupp = orguNumbSupp; } public void setPymtMthdCode(String pymtMthdCode) { this.pymtMthdCode = pymtMthdCode; } public void setShptNumb(Long shptNumb) { this.shptNumb = shptNumb; } public void setUomCode(String uomCode) { this.uomCode = uomCode; } public void setUomCodeDistBss(String uomCodeDistBss) { this.uomCodeDistBss = uomCodeDistBss; } public void setUomCodeWght(String uomCodeWght) { this.uomCodeWght = uomCodeWght; } public void setXCnt(long xCnt) { this.xCnt = xCnt; } }

Edit, BazB: added readmore tag. Edit 2: close said readmore. Doh.

Replies are listed 'Best First'.
Re: This is why I use Perl
by perrin (Chancellor) on Nov 07, 2003 at 18:26 UTC
    I've had similar experiences at Java-oriented development shops where people didn't realize how easy it is to, say, parse a bunch of Oracle DDL and reformat it while moving the constraints to a separate file and renaming them. They didn't know Perl, or any other scripting language, so this sounded like an impossible task.

    By the way, did you consider using Hibernate or something similar for these data objects?

Re: This is why I use Perl
by BUU (Prior) on Nov 08, 2003 at 03:50 UTC
    Question, if yer just going to generate accessors for every single property, why not just make them public?

      Good question.

      If you allow, let me answer it by giving a simple example. Say we have a class that represents date, for example 2003-11-07, and one of its property is month.

      • If I make this property public, someone uses this class, can easily set month to 13. Well, this could be well valid for some calendars, but not for this calendar that most of us use. So we opened up a hole for error by make it public. To avoid this error, we have to implement the checking logic in every single piece of code uses this class.
      • Now if we make it private, and in the setter, we check whether month is less than or equal to 12, we only need to implement this logic once for good.
        In some languages (eg Ruby) this isn't a good reason since it is trivial to implement get/set methods that will be visible and manipulatable outside of the class exactly how the old attribute was. So you can start with every property public, and then fix ones which in retrospect shouldn't have been. So you don't worry about it until you have to.

        You can do the same in Perl if you are willing to retrofit a tie on an existing class. (Admittedly at a considerable speed hit.) This is sufficiently obscure and confusing that the decision to do it is certainly making demands on the maintainance programmer.

        I don't know Java well enough to know whether this strategy is possible there, but I strongly doubt it. (Corrections or confirmation welcome.)

        Example: first we set day to 30. All is well. Next we set month to 2. All is still well, except that the 30th of February isn't valid.

        Let's do it the other way around: currently the month is set to 2. We try to set day to 30, but the system won't allow it, because the 30th of February isn't valid. We were going to set the month later, you bozo system!

        Lesson to be learned: don't let the system do your thinking.

        I don't like overzealous range testing for each individual field, in this example because the ranges themselves are interdependent. Having a get/set interface won't help one single bit.

        Instead, I only want the system to check if the date is valid, when I'm trying to use the date (in case of a Javascript on a HTML form: when trying to submit the form). In perl, for often used checks, you still can have some speed boost by caching, either by checking if the date has changed since last time, before checking again, or some use of a Memoize cache on the function value.

Re: This is why I use Perl
by Anonymous Monk on Nov 08, 2003 at 17:52 UTC
    Why should you use Perl? Wheneven others ask this question, I always say, there is no way you can develop this faster in other languages than do it in Perl.

    I think you need to clarify that point a little. There may be no way you can develop this faster in other languages, but there are several other languages that would allow for equal ease of development: Ruby and Python for sure (but also Lua, Icon, and Lisp are good candidates). Don't confuse: "Best tool for the job" with "Best tool for your mind". There is absolutely nothing wrong with the latter justification when selecting among a set of relatively equally capable tools, but it is incorrect to equate this with some superiority of the chosen tool.

      Don't confuse: "Best tool for the job" with "Best tool for your mind".

      Yes, I have absolutely no problem with this statement, and it is such a basic fact, thus there is no need for people to explicitly state it everytime. On the other hand, you have to recognize that whatever decision you reached is always the "best tool for your mind", as decision is always made within the knowledge boundary of the person or the group of persons, and also their biased preferrence. We are not perfect, are we ;-?

      They are some very nice languages but what they are lacking is an equivalent to CPAN. And CPAN is my answer to the OP.
Re: This is why I use Perl
by adrianh (Chancellor) on Nov 10, 2003 at 00:58 UTC
    I decided to code a tool to generate those DCO’s. Obviously I did it in Perl, and it only took me half hour.

    You might be interested in Chris Winter's YAPC 2003 talk "Generating Java with Perl". The slides and an mp3 are available.

Re: This is why I use Perl
by Art_XIV (Hermit) on Nov 10, 2003 at 15:16 UTC

    pg -
    I can say from experience that you can generate (or at least partially generate) the data-access methods that will generate your value classes, too. It's not very hard to generate classes that will handle simple CRUD/db work, and it can be even easier if you already have a set of stored procedures for data access.

    Code-generation can be very fun and highly productive. When done even half-skillfully, it can lead to a larger percentage of bug-free code.

    I am often suprised at the number of developers who have no clue about how to proceed w/ code generating ventures. I've come across dozens of degree-holding, experienced developers who would be more than happy to hand-code a hundred or more value classes and their corresponding method calls. I often wonder if it's a matter of simple indifference.

    And after many iterations of having used Perl to make some job easier, I find myself asking more and more often 'Why in the h*ll don't I just use Perl for the whole thing?'

    Hanlon's Razor - "Never attribute to malice that which can be adequately explained by stupidity"