Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using marshaller / unmarshaller are very buggy #12

Closed
bbottema opened this issue Jun 15, 2016 · 1 comment
Closed

Using marshaller / unmarshaller are very buggy #12

bbottema opened this issue Jun 15, 2016 · 1 comment

Comments

@bbottema
Copy link

bbottema commented Jun 15, 2016

I'm running into all kinds of bugs, NullPointers, ClassCast exceptions inside the framework, validation errors. I'm not able to get the following to work at all, although I'm already working around several bugs.

Following are the following components: annotated record class, fixed width JMS message converter config + typehandlers, and junit test class. The JMS parts can be removed.

I don't think it should be very difficult: map between fixed width string to annotated class and back. I couldn't find any junit tests also in your code base that touches this.

Annotated Record class

import org.beanio.annotation.Field;
import org.beanio.annotation.Record;

import java.math.BigDecimal;
import java.util.Date;

import static org.beanio.builder.Align.LEFT;
import static org.beanio.builder.Align.RIGHT;

@Record(minOccurs = 1)
public class InputVariablesDto {

    // INVOER-SEGMENT

    @Field(at = 0, length = 3, align = RIGHT, padding = '0')
    private Integer renteBerichtCode;

    @Field(at = 1, length = 8, format = "yyyyMMdd")
    private Date renteBerichtDat;

    @Field(at = 2, length = 3, align = RIGHT, padding = '0')
    private Integer renteVastPeriode;

    @Field(at = 3, length = 1, handlerName = "JaNeeTypeHandler")
    private Boolean nhgInd;

    @Field(at = 4, length = 12, align = RIGHT, handlerName = "LisDecimalTypeHandler", padding = '0')
    private BigDecimal marktwaardeFactor;

    // UITVOER-SEGMENT

    @Field(at = 5, length = 4, align = RIGHT, padding = '0')
    private String foutKode;

    @Field(at = 6, length = 120, align = LEFT, padding = ' ')
    private String foutOms;

    @Field(at = 7, length = 12, align = RIGHT, padding = '0', handlerName = "LisDecimalTypeHandler")
    private BigDecimal actHypRente;

    public Integer getRenteBerichtCode() {
        return renteBerichtCode;
    }

    public void setRenteBerichtCode(Integer renteBerichtCode) {
        this.renteBerichtCode = renteBerichtCode;
    }

    public Date getRenteBerichtDat() {
        return renteBerichtDat;
    }

    public void setRenteBerichtDat(Date renteBerichtDat) {
        this.renteBerichtDat = renteBerichtDat;
    }

    public Integer getRenteVastPeriode() {
        return renteVastPeriode;
    }

    public void setRenteVastPeriode(Integer renteVastPeriode) {
        this.renteVastPeriode = renteVastPeriode;
    }

    public Boolean getNhgInd() {
        return nhgInd;
    }

    public void setNhgInd(Boolean nhgInd) {
        this.nhgInd = nhgInd;
    }

    public BigDecimal getMarktwaardeFactor() {
        return marktwaardeFactor;
    }

    public void setMarktwaardeFactor(BigDecimal marktwaardeFactor) {
        this.marktwaardeFactor = marktwaardeFactor;
    }

    public String getFoutKode() {
        return foutKode;
    }

    public void setFoutKode(String foutKode) {
        this.foutKode = foutKode;
    }

    public String getFoutOms() {
        return foutOms;
    }

    public void setFoutOms(String foutOms) {
        this.foutOms = foutOms;
    }

    public BigDecimal getActHypRente() {
        return actHypRente;
    }

    public void setActHypRente(BigDecimal actHypRente) {
        this.actHypRente = actHypRente;
    }
}

Fixed width JMS message converter config and typehandlers

import InputVariablesDto;
import org.beanio.Marshaller;
import org.beanio.StreamFactory;
import org.beanio.Unmarshaller;
import org.beanio.builder.FixedLengthParserBuilder;
import org.beanio.builder.StreamBuilder;
import org.beanio.internal.parser.MarshallerImpl;
import org.beanio.types.TypeConversionException;
import org.beanio.types.TypeHandler;
import org.springframework.jms.support.converter.MessageConversionException;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import java.math.BigDecimal;

import static org.apache.commons.lang.StringUtils.*;

public class FixedWithMessageConverter implements org.springframework.jms.support.converter.MessageConverter {

    private static final Marshaller marshaller;
    private static final Unmarshaller unmarshaller;

    static {
        StreamFactory factory = StreamFactory.newInstance();
        factory.define(new StreamBuilder("inputVariables")
                .format("fixedlength")
                .parser(new FixedLengthParserBuilder())
                .addTypeHandler("JaNeeTypeHandler", new JaNeeTypeHandler())
                .addTypeHandler("LisDecimalTypeHandler", new LisDecimalTypeHandler())
                .addRecord(InputVariablesDto.class));
        unmarshaller = factory.createUnmarshaller("inputVariables");
        marshaller = factory.createMarshaller("inputVariables");
    }

    @Override
    public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException {
        if (!(object instanceof InputVariablesDto)) {
            throw new IllegalArgumentException("expected InputVariablesDto but was: " + object.getClass());
        }
        String[] strings = ((MarshallerImpl) marshaller.marshal(object)).toArray();
        return session.createTextMessage(join(strings));
    }

    @Override
    public Object fromMessage(Message message) throws JMSException, MessageConversionException {
        if (!(message instanceof TextMessage)) {
            throw new IllegalArgumentException("unknown message type: " + message.getClass());
        }
        return unmarshaller.unmarshal(((TextMessage) message).getText());
    }

    /**
     * Domain: J = With NHG (true), N = Without NHG (false)
     */
    private static class JaNeeTypeHandler implements TypeHandler {
        @Override
        public Object parse(String text) throws TypeConversionException {
            return "J".equals(text);
        }

        @Override
        public String format(Object value) {
            return ((Boolean) value) ? "J" : "N";
        }

        @Override
        public Class<?> getType() {
            return Boolean.class;
        }
    }

    /**
     * Format: ‘+00000,00000’ Example: ‘+00000,90000’
     */
    private static class LisDecimalTypeHandler implements TypeHandler {
        @Override
        public Object parse(String text) throws TypeConversionException {
            return new BigDecimal(text.replace(',', '.'));
        }

        @Override
        public String format(Object value) {
            BigDecimal bigDecimal = (BigDecimal) value;
            bigDecimal.setScale(5);
            String signum = bigDecimal.signum() == -1 ? "" : "+";
            String strValue = bigDecimal.toPlainString().replace('.', ',');
            String mainValue = strValue.substring(0, strValue.indexOf(','));
            String fractionValue = strValue.substring(strValue.indexOf(',') + 1, strValue.length());
            return String.format("%s%s,%s", signum, leftPad(mainValue, 5, '0'), rightPad(fractionValue, 5, '0'));
        }

        @Override
        public Class<?> getType() {
            return BigDecimal.class;
        }
    }
}

Junit test

import InputVariablesDto;
import org.joda.time.DateTime;
import org.junit.Test;
import org.mockito.ArgumentCaptor;

import javax.jms.JMSException;
import javax.jms.Session;
import javax.jms.TextMessage;
import java.math.BigDecimal;

import static org.assertj.core.api.Assertions.assertThat;
import static org.joda.time.format.DateTimeFormat.forPattern;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class FixedWithMessageConverterTest {

    private FixedWithMessageConverter converter = new FixedWithMessageConverter();

    private final DateTime VANDAAG = DateTime.now();

    @Test
    public void toMessage() throws JMSException {
        Session mockedSession = mock(Session.class);
        ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
        when(mockedSession.createTextMessage(captor.capture())).thenReturn(null);
        converter.toMessage(createListObject(), mockedSession);

        String datumStr = forPattern("yyyyMMdd").print(VANDAAG);
        String oms = "omschrijving                                                                                                            ";
        assertThat(captor.getValue()).isEqualTo("001" + datumStr + "044" + "J" + "+00000,90000" + "0001" + oms + "+00005,75000");
    }

    @Test
    public void fromMessage() throws JMSException {
        String fixedWidthMsg = "00120160615044J+00000,900000001omschrijving                                                                                                            +00005,75000";
        TextMessage tm = mock(TextMessage.class);
        when(tm.getText()).thenReturn(fixedWidthMsg);
        String result = (String) converter.fromMessage(tm);
        assertThat(result).isNotEqualTo(createListObject());
    }

    private InputVariablesDto createListObject() {
        InputVariablesDto dto = new InputVariablesDto();
        dto.setRenteBerichtCode(1);
        dto.setRenteBerichtDat(VANDAAG.toDate());
        dto.setRenteVastPeriode(44);
        dto.setNhgInd(true);
        dto.setMarktwaardeFactor(new BigDecimal("0.9"));
        dto.setFoutKode("1");
        dto.setFoutOms("omschrijving");
        dto.setActHypRente(new BigDecimal("5.75"));
        return dto;
    }
}
@bbottema bbottema changed the title Using marshaller / unmarshaller is very buggy Using marshaller / unmarshaller are very buggy Jun 15, 2016
@bbottema
Copy link
Author

bbottema commented Jun 15, 2016

I didn't set the at = attributes correctly (I though beanio would figure out the absolute position using the length attribute).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant