Can I have multiple bindy annotated classes in a package and still unmarshal CSVs in Camel?

StackOverflow https://stackoverflow.com/questions/16408839

  •  14-04-2022
  •  | 
  •  

質問

I would like to have a package like my.company.bindy with several classes in it all annotated with Bindy annotations. Then I'd like to have Camel routes that can unmarshal CSV into one of these types. I've got it all working, but unmarshalling fails if I have more than one bindy annotated class in the package. This because Bindy is trying to unmarshal the CSV line into every class in the package. And a particular line won't properly marshal into more than one of the classes. My dataformat is declared in Spring like this:

<bean class="org.apache.camel.dataformat.bindy.csv.BindyCsvDataFormat">
    <property name="packages" value="my.company.bindy"/>
</bean>
役に立ちましたか?

解決

This issue has been fixed with Camel 2.16.0.

From http://camel.apache.org/bindy.html

"If you use multiple models, each model has to be placed in it's own package to prevent unpredictable results.

From Camel 2.16 onwards this is no longer the case, as you can safely have multiple models in the same package, as you configure bindy using class names instead of package names now."

他のヒント

My solution to this was to extend BindyCsvDataFormat as follows:

/**
* This class changes the behavior of BindyCsvDataFormat. Instead of detecting classes
* in package(s) which are annotated with bindy annotations, this class, specifically
* defines the class that will be unmarshalled into.
*/
public class SingleClassBindyCsvDataFormat extends BindyCsvDataFormat {

private Class<?> modelClass;

@Override
protected BindyAbstractFactory createModelFactory(PackageScanClassResolver resolver) throws Exception {
    return new OneClassBindyCsvFactory(resolver, getModelClass());
}

@Override
public void setPackages(String... packages) {
    throw new UnsupportedOperationException("This dataformat does not support package based model searches.");
}

public Class<?> getModelClass() {
    return modelClass;
}

public void setModelClass(Class<?> modelClass) {
    this.modelClass = modelClass;
}

private static class OneClassBindyCsvFactory extends BindyCsvFactory {

    public OneClassBindyCsvFactory(PackageScanClassResolver resolver, Class<?> modelClass) throws Exception {
        super(resolver, new String[]{});
        Preconditions.checkNotNull(modelClass);
        models = ImmutableSet.<Class<?>>of(modelClass);
        initCsvModel();
    }

}

}

So far, it works like a charm!

I came across the same sort of problem using the Java DSL. I had two classes annotated with Bindy and the "wrong" class was getting instantiated.

The solution in that instance was to fully qualify the package name that I bound to

E.g.

from("file:myfile.csv").
  unmarshall().
    bindy(BindyType.Csv, com.company.domain.OrderLine.class).
to("seda:output")

rather than

from("file:myfile.csv").
  unmarshall().
    bindy(BindyType.Csv, OrderLine.class).
to("seda:output")

My answer would be the same as above but with much more clear code. I tried it in my project and it works fine.

import org.apache.camel.dataformat.bindy.BindyAbstractFactory;
import org.apache.camel.dataformat.bindy.BindyCsvFactory;
import org.apache.camel.dataformat.bindy.csv.BindyCsvDataFormat;
import org.apache.camel.spi.PackageScanClassResolver;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;

public class CustomBindyCsvDataFormat extends BindyCsvDataFormat {

private Class<?> modelClass;

public CustomBindyCsvDataFormat(Class<?> modelClass) {
    this.modelClass = modelClass;
}

public Class<?> getModelClass() {
    return modelClass;
}

@Override
protected BindyAbstractFactory createModelFactory(PackageScanClassResolver resolver) throws Exception {

    return new CustomBindyCsvFactory(resolver, getModelClass());
}

private class CustomBindyCsvFactory extends BindyCsvFactory {

    public CustomBindyCsvFactory(PackageScanClassResolver resolver, Class<?> modelClass) throws Exception {
        super(resolver, new String[] {});
        Preconditions.checkNotNull(modelClass);
        models = ImmutableSet.of(modelClass);
        initCsvModel();
    }

}

}

And instead of calling BindyCsvDataFormat with packageName as string args we can use CustomBindyCsvDataFormat with fully qualified class names as argument.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top