Java -> Cobol serialization

364 views
Skip to first unread message

patrick

unread,
Jun 10, 2011, 10:44:21 AM6/10/11
to legstar-user
Hi,
I'm developing a Java application that needs to send data to
mainframe COBOL. With that said, I'm generating an XSD from existing
Java classes, and then generating a transformer and binding classes
from this XSD. I'm getting hung on a simple field type...
java.util.Date. JAXB tries to use XMLGregorianCalendar, Legstar
defines it as type="ALPHANUMERIC_ITEM" and the whole thing goes awry.
The generated Binding class is wrong, and I get either compile-time
errors or runtime exceptions depending on how I try to work around it.
Is there any way I can specify some kind of adapter... an
ICobolStringBinding to convert from alpha-numeric to my Java type and
specify this as an annotation on my java class? Similar to the way I
would use "@XmlJavaTypeAdapter"? I need to specify some kind of
adapter, how would I configure Legstar to serialize complex types?
--
Patrick

Fady

unread,
Jun 10, 2011, 1:12:32 PM6/10/11
to legstar-user
Hello Patrick,

The short answer is that there is no support for java.util.Date at the
moment and no extension mechanism that allows you to overcome that (I
like your idea of mimicking XmlJavaTypeAdapter).

This being said I looked at the code and I think we could introduce
some minimal support for java.util.Date by doing something this like
this:

1. changing coxbgen so that it generates additional JAXB customization
if it encounters an xs:dateTime. This should resolve the compilation
issue you are hitting with XMLGregorianCalendar.
2. changing coxbrt to convert Date to a string by simply calling
Date#toString(). This should resolve the execution error you are
probably hitting.

The result should be that you mainframe will receive a PIC X(32)
containing a string representation of the Date.

The first item is harder than the second but it looks like you found
your way around it.

What I propose is to generate a snapshot of legstar-core with the
second change for you and we'll take it from there.

Let me know if that would work for you.

Fady

patrick

unread,
Jun 10, 2011, 3:48:54 PM6/10/11
to legstar-user
I'm glad you understood what I was talking about off the bat. I wasn't
sure if I was being clear enough without any examples. I'm new to
legstar, but very excited about it.

I've managed to get some of this working... if I modify the auto-
generated CComplexBinding subclass to use Date's toString(). I could
potentially modify the bindings to use a custom adapter.

_payEndDate.setObjectValue(mValueObject.getPayEndDate().toString());

and

bindingValue = new Date((String)child.getObjectValue(String.class)); //
using deprecated constructor just for a simple illustration.
mValueObject.setPayEndDate((Date) bindingValue);

The problem is that these bindings are auto-generated from source
files that I'm auto-generating myself from templates :) That is, the
java source POJO's that I need to map between Java and Cobol are
generated from velocity templates, compiled by my build script, then I
want to call legstar to produce the bindings and transformers. I need
to be able to specify an adapter of some kind. I'm thinking I might
write my own extension to AbstractTransformer that allows this through
some fancy binding implementation... and uses reflection and
@CobolElement annotations instead of generating an XSD and Bindings.

How difficult do you think this would be to implement? I could
potentially create an @CobolJavaTypeAdapter that specifies a custom
handler or ICobolStringBinding for a field. Essentially a factory that
knows how to convert to/from a string for some other type... like a
Date, Enum, etc. Could you provide any direction? It strikes me as
being similar to Hibernate UserType's

Fady

unread,
Jun 11, 2011, 4:02:35 AM6/11/11
to legstar-user
Hello Patrick,

First of all, there is a snapshot with minimal date support here:
https://oss.sonatype.org/content/repositories/snapshots/com/legsem/legstar/legstar-coxbgen/1.5.4-SNAPSHOT/legstar-coxbgen-1.5.4-20110411.063404-2-bin.zip

You can see the code changes here:
http://code.google.com/p/legstar/source/diff?spec=svn1815&r=1815&format=side&path=/trunk/legstar-core/legstar-coxbrt/src/main/java/com/legstar/coxb/impl/AbstractAlphaNumericBinding.java

This is close to the code you are suggesting. Just using
java.sql.Timestamp to avoid deprecated Date constructors and also
because Timestamp#toString() has a more universal format: "yyyy-mm-dd
hh:mm:ss.fffffffff" that fits in a PIC X(32) and would be easy to
parse in COBOL.

If I understand what you are trying to accomplish: generating
annotated POJOs from velocity templates, bypassing the java2cob and
coxbgen utilities, you are probably going to need more flexibility. If
you take a look at the test class here:
http://code.google.com/p/legstar/source/browse/trunk/legstar-core/legstar-coxbrt/src/test/java/com/legstar/coxb/impl/StringDateTest.java?spec=svn1815&r=1815
you will notice that it avoids the binding generation step altogether.

This code only uses the annotated POJO using reflection. There are a
number of visitors in LegStar and you can implement your own. By
deriving your visitor from one of LegStar, you can leverage the
LegStar code and substitute your own conversion code where you see
fit.

I will have to spend more time looking into your @CobolJavaTypeAdapter
idea. I am not sure how to deal with it yet.

Let us know how it goes.


Fady

patrick

unread,
Jun 13, 2011, 7:51:04 AM6/13/11
to legstar-user
Well, if I ever do find the time and justification to do the adapter
idea, I'll be more than happy to offer up my suggestions. The problem
is that I probably won't have time to integrate it well with your
codebase; it might be a little sloppily hacked together. I think it
will end up requiring a subclass of CComplexBinding that supports an
adapter. In the non-reflection case these field bindings are generated
by ant scripts, which would make it difficult for me to add support
for this. I'll probably write it into some extension of the reflection-
based method, and it would have to be integrated later.

I've seen the reflection-based transformer. I'm certainly going to
make use of it, but one thing that's missing here is support for
implicit cobol types. Using JAXB you don't need to explicitly define
the XMLType, but it will use whatever is default for the field's type
unless otherwise declared. Legstar could and should do the same for
@CobolElement, although it would require some coupling with the
translator module. Can you point me to the translator code that would
allow me to reflect and decide on a default/implicit cobol type at
runtime?
--
Patrick

On Jun 11, 4:02 am, Fady <fady.moussal...@gmail.com> wrote:
> Hello Patrick,
>
> First of all, there is a snapshot with minimal date support here:https://oss.sonatype.org/content/repositories/snapshots/com/legsem/le...
>
> You can see the code changes here:http://code.google.com/p/legstar/source/diff?spec=svn1815&r=1815&form...
>
> This is close to the code you are suggesting. Just using
> java.sql.Timestamp to avoid deprecated Date constructors and also
> because Timestamp#toString() has a more universal format: "yyyy-mm-dd
> hh:mm:ss.fffffffff" that fits in a PIC X(32) and would be easy to
> parse in COBOL.
>
> If I understand what you are trying to accomplish: generating
> annotated POJOs from velocity templates, bypassing the java2cob and
> coxbgen utilities, you are probably going to need more flexibility. If
> you take a look at the test class here:http://code.google.com/p/legstar/source/browse/trunk/legstar-core/leg...

Fady Moussallam

unread,
Jun 13, 2011, 9:08:38 AM6/13/11
to legsta...@googlegroups.com
yes, that is right, there is no support for implicit types. The
@CobolElement is currently mandatory.

I guess the best place to provide a default would be around line 233 in
http://code.google.com/p/legstar/source/browse/trunk/legstar-core/legstar-coxbrt/src/main/java/com/legstar/coxb/impl/reflect/CComplexReflectBinding.java.

Otherwise, just to make it clear, in legstar, the translation process,
when the starting point is a POJO, has 2 steps (see
http://code.google.com/p/legstar-xsd2cob/) :

1. Use JAXB schemagen to produce an XSD out of the POJO
2. Parse the XSD and produce a COBOL-annotated XSD (this is where
mapping XSD types to COBOL types takes place)

Then the binding process again has 2 steps:

3. Use JAXB xjc to produce a COBOL-annotated POJO. This is where
@CobolElement annotations, which are derived from the XSD COBOL
annotations produced at step 2, are injected in the JAXB POJO
4. Reflect on the COBOL-annotated POJO to produce binding classes

At runtime, you have the choice of using the output from step 4, using
transformers, which has the best performances, or the output of step 3,
using reflection, like I did in my last reply.

In summary, there are 2 difficulties here:

1. legstar does not infer a COBOL type directly from a java type. An
intermediary XSD type is used instead.
2. Type inference happens in a different tool (xsd2cob) than binding
(coxbrt)

so it seems to me relatively difficult at this stage to support implicit
types.

Fady

patrick

unread,
Jun 13, 2011, 3:16:58 PM6/13/11
to legstar-user
Okay, we're on the same page. I appreciate the help. I think what I'll
end up doing will be helpful to me, but won't mesh too well with the
rest of the codebase. I'll just explicitly annotate @CobolElement on
my POJOs because they're already riddled with javax.persistence
annotations. I can't use xjc unless it respects everything else I have
written into the class like static fields, comments, and annotations.
I'm going to guess that it dumps a simple POJO with cobol annotations
only. It's from a template, right?

in CComplexReflectBinding.createBinding I'm planning on doing
something similar to how you create a dynamic counter. After the type
binding is made, I'll wrap any fields that have @CobolTypeAdapter
annotations which will convert to/from the non-primitive type.

This is a great library, btw. Thanks.
--
Patrick

On Jun 13, 9:08 am, Fady Moussallam <fady.moussal...@gmail.com> wrote:
> yes, that is right, there is no support for implicit types. The
> @CobolElement is currently mandatory.
>
> I guess the best place to provide a default would be around line 233 inhttp://code.google.com/p/legstar/source/browse/trunk/legstar-core/leg....
>
> Otherwise, just to make it clear, in legstar, the translation process,
> when the starting point is a POJO, has 2 steps (seehttp://code.google.com/p/legstar-xsd2cob/) :

patrick

unread,
Jun 14, 2011, 3:51:58 PM6/14/11
to legstar-user
Fady,
I've successfully implemented most of what I need. I can't seem to
make sense of the createDynamicCounter stuff for supporting Lists of
my adapted bindings. When I mark my Pojo as so...

@CobolTypeAdapter(type = DateStringBindingAdapter.class)
@CobolElement(type = CobolType.ALPHANUMERIC_ITEM, cobolName =
"myCobolDate", picture = "X(32)", maxOccurs = 10, minOccurs = 1)
private List<Date> myDate = new LinkedList<Date>();

It uses the Binding type below, that basically wraps what's created by
"createBinding" in CComplexReflectBinding with an implementation that
delegates to the created binding, but converts with the adapter when a
value is set or retrieved.

public class AdaptedCobolBinding implements ICobolBinding {

@Override
public void setObjectValue(Object arg0) throws HostException {
Object value = this.adapter.convertTo(arg0);
binding.setObjectValue(value);
}


Now in AdaptedCobolBinding, the argument comes in as a List, which is
not what I would expect. I believe the counter should be used to set
the value on the appropriate object index? I really can't seem to find
how this is handled for simple Lists of primitives. My createBinding
mod looks something like this after all of the switch/case statements.

/* We might need to wrap it if there's an adapter.
*/
CobolTypeAdapter adapterAnnotation = hostField
.getAnnotation(CobolTypeAdapter.class);
cobolElement (adapterAnnotation == null) ? cobolElement : new
AdaptedCobolBinding(
cobolElement, adapterAnnotation);
/*
* If this element is a variable size array or list without an
explicit
* depending on clause, dynamically generate a counter.
*/
if (cobolAnnotations.maxOccurs() > 1
&& cobolAnnotations.minOccurs() <
cobolAnnotations.maxOccurs()
&& (cobolAnnotations.dependingOn() == null ||
cobolAnnotations
.dependingOn().length() == 0)) {
createDynamicCounter(cobolElement);
}
--
Patrick

Fady Moussallam

unread,
Jun 15, 2011, 3:17:01 AM6/15/11
to legsta...@googlegroups.com
On 14/06/2011 21:51, patrick wrote:
> I believe the counter should be used to set
> the value on the appropriate object index?
No it is not. The dynamic counter is there because at the end of the
day, you will have to produce a valid COBOL structure. COBOL variable
size arrays are the best (the only possible actually) mapping for a
java.util.List.

COBOL variable size arrays are declared like so:

05 SOME-COUNTER PIC 99.
05 VSARRAY OCCURS 1 TO 100 DEPENDING ON SOME-COUNTER.
10 ...

As you can see the array size can vary at runtime but the actual size
must be given by the SOME-COUNTER counter.

Now for legstar, when the starting point is java (or XSD), lists are
mapped to such an array and counter. That counter is qualified of
dynamic because it does not map any field from the original POJO and it
is added on the fly at binding time.

In addition to generating an extra binding for the counter, legstar also
has code to keep the value of the counter equal to the array size (java
-> cobol). The code that does that shows up in
com.legstar.coxb.common.CArrayBinding#getCurrentOccurs(). Similarly,
upon receiving mainframe data (cobol -> java), the counter tells legstar
when to stop marshaling data for the array.

Hope this helps.

Fady

patrick

unread,
Jun 15, 2011, 9:15:31 AM6/15/11
to legstar-user
I'm being told by my mainframe developer that the syntax for variable
arrays like so requires the keyword "TIMES" like: "OCCURS X TO Y TIMES
DEPENDING ON SOME-COUNTER". The copybook generator doesn't seem to be
correct.

I've gotten the marshalling working (albeit untested on the mainframe)
to byte[] and back using Lists, but I can't seem to get the java2cob
generator to write a counter out into the copybook. Also, java2cob
doesn't seem to respect my @CobolElement annotations. If I define min/
max occurs or a cobolName, the generated copybook seems to get written
with defaults.

So I'm wondering what the copybook needs to look like if I do
something like the following. I assume writing "dependingOn" will
generate a dynamic counter for me using a pre-defined name. Is this
the case?
@CobolTypeAdapter(type = DateStringBindingAdapter.class)
@CobolElement(type = CobolType.ALPHANUMERIC_ITEM, cobolName =
"myCobolDate", picture = "X(10)", maxOccurs = 99, minOccurs = 6,
dependingOn="date-counter")
private List<Date> myDate = new LinkedList<Date>();

The auto-generated copybook shows me this.
03 myDate PIC X(32) OCCURS 0 TO 10.

Do I have to modify this auto-copybook to look like this? Or is there
a way to get it generated correctly?
05 date-counter PIC S9(9) COMP-5
03 myDate PIC X(32) OCCURS 6 TO 99 TIMES DEPENDING ON date-
counter.

Fady Moussallam

unread,
Jun 15, 2011, 9:59:22 AM6/15/11
to legsta...@googlegroups.com
This is actually a bug in java2cob, it should generate the additional
counters.

This being said, there is another utility within legstar called cobcgen
that is used internally to generate COBOL using the JAXB class directly
(the one with annotations).

cobcgen is an ant task but you can also use it programmatically like so:

----------------------------------------------------------------------------------
package com.legsem.test;

import java.io.File;
import java.io.IOException;

import junit.framework.TestCase;

import org.apache.commons.io.FileUtils;
import org.apache.tools.ant.BuildException;

import com.legstar.cobc.gen.CobolGenerator;


public class CobolGenTest extends TestCase {

private static final File GEN_DIR = new File("target");

public void testGen() throws Exception {
try {
CobolGenerator gen = new CobolGenerator();
gen.setJaxbTypeName("MyDateClass");
gen.setJaxbPackageName("legstar.trans.patrick");
gen.setTargetDir(GEN_DIR);
gen.execute();
String cobol = FileUtils.readFileToString(new File(GEN_DIR,
"MyDateClass.cbl"), "UTF-8");
assertEquals("", cobol);
} catch (BuildException e) {
fail(e.getMessage());
} catch (IOException e) {
fail(e.getMessage());
}
}

}
----------------------------------------------------------------------------------

Can you give it a try?

Fady

P.S. TIMES is not mandatory with Enterprise COBOL for z/OS. legstar is
not guaranteed to work with any other COBOL compiler

patrick

unread,
Jun 15, 2011, 10:12:03 AM6/15/11
to legstar-user
What module is this supposed to be in? I have the eclipse plugin
installed, and legstar was added to my main project, but I'm trying to
run my tests with the individual modules.
I see it's in legstar-cobcgen-1.5.3.jar, but I can't find that in any
of the modules. I'll be happy to try it as soon as I find it.

Fady Moussallam

unread,
Jun 15, 2011, 10:23:38 AM6/15/11
to legsta...@googlegroups.com
On 15/06/2011 16:12, patrick wrote:
> What module is this supposed to be in? I have the eclipse plugin
> installed, and legstar was added to my main project, but I'm trying to
> run my tests with the individual modules.
> I see it's in legstar-cobcgen-1.5.3.jar, but I can't find that in any
> of the modules. I'll be happy to try it as soon as I find it.
>
legstar-cobcgen is bundled with legstar-coxbgen (its part of the
legstar-core project). You can download the bundle from here:
http://www.legsem.com/legstar/legstar-core/legstar-coxbgen/download.html.

If you use Maven, you can get it like so (it is in Maven central):

<dependency>
<groupId>com.legsem.legstar</groupId>
<artifactId>legstar-cobcgen</artifactId>
<version>1.5.3</version>
</dependency>

Let me know how it goes.

Fady

patrick

unread,
Jun 15, 2011, 10:24:36 AM6/15/11
to legstar-user
I've just linked to the distribution for the purposes of the test, but
does this mean there's a "core" module that isn't listed under the
individual module page?

CobolGenerator seemed to work correctly. The only annoying part is it
requires me to have an empty "ObjectFactory" class in the package, but
I think that's a JAXB requirement.

01 DummyPojo.
02 myDate--C PIC 9(9) BINARY.
02 other--C PIC 9(9) BINARY.
02 myCobolField PIC X(32).
02 myDate PIC X(32) OCCURS 1 TO 100 DEPENDING ON myDate--C.
02 R-other OCCURS 0 TO 99 DEPENDING ON other--C.
03 myInteger PIC S(9).
03 myString PIC X(32).
03 myBoolean PIC 9(1).


I'll need to work with my mainframe developer to check that all of
this is being written correctly, but I finally have a good copybook.
Thank you.
--
Patrick

Fady Moussallam

unread,
Jun 16, 2011, 8:03:26 AM6/16/11
to legsta...@googlegroups.com
On 15/06/2011 16:24, patrick wrote:
> I've just linked to the distribution for the purposes of the test, but
> does this mean there's a "core" module that isn't listed under the
> individual module page?
>
> CobolGenerator seemed to work correctly. The only annoying part is it
> requires me to have an empty "ObjectFactory" class in the package, but
> I think that's a JAXB requirement.
>
> 01 DummyPojo.
> 02 myDate--C PIC 9(9) BINARY.
> 02 other--C PIC 9(9) BINARY.
> 02 myCobolField PIC X(32).
> 02 myDate PIC X(32) OCCURS 1 TO 100 DEPENDING ON myDate--C.
> 02 R-other OCCURS 0 TO 99 DEPENDING ON other--C.
> 03 myInteger PIC S(9).
> 03 myString PIC X(32).
> 03 myBoolean PIC 9(1).
>
>
> I'll need to work with my mainframe developer to check that all of
> this is being written correctly, but I finally have a good copybook.
> Thank you.
> --
> Patrick
I am quite impressed with what you were able to do, Patrick.
Congratulations.

Hopefully, the copybook will work out for you mainframe people.

I guess we could have done without the JAXB objectfactory in most cases
but there are circumstances when it is necessary (Typically when
JAXBElement wrappers are needed).

Also, sorry for the confusion about legstar-core versus legstar-coxbgen.
legstar-core is a Maven parent POM (no code there) for a number of
subprojects, legstar-coxbgen being one of them. There should be a
legstar-core distributable but currently, all the legstar-core
subprojects are distributed as part of legstar-coxbgen for historical
reasons. So when you download legstar-coxbgen, you actually get all the
legstar-core modules.

Fady


Reply all
Reply to author
Forward
0 new messages