Does ChronicleWire support optional fields in entities? - chronicle

I am experimenting with ChronicleWire. As described in features optional fields are supported out of the box.
I just created a simple self-describing entity with one optional (nullable) field:
public class Foo extends SelfDescribingMarshallable {
private String name;
private Baz baz;
}
where baz might or might not be null and implements/extends Marshallable.
When I try to put entity to ChronicleMap I get an error:
Exception in thread "main" java.lang.NullPointerException
at net.openhft.chronicle.bytes.BytesMarshaller$BytesMarshallableFieldAccess.getValue(BytesMarshaller.java:211)
at net.openhft.chronicle.bytes.BytesMarshaller$FieldAccess.write(BytesMarshaller.java:152)
at net.openhft.chronicle.bytes.BytesMarshaller.writeMarshallable(BytesMarshaller.java:70)
at net.openhft.chronicle.bytes.BytesUtil.writeMarshallable(BytesUtil.java:295)
at net.openhft.chronicle.bytes.BytesMarshallable.writeMarshallable(BytesMarshallable.java:48)
at net.openhft.chronicle.bytes.BytesMarshaller$BytesMarshallableFieldAccess.getValue(BytesMarshaller.java:211)
at net.openhft.chronicle.bytes.BytesMarshaller$FieldAccess.write(BytesMarshaller.java:152)
When I tried to use java optional instead and my entity changed to:
public class Foo extends SelfDescribingMarshallable {
private String name;
private Optional<Baz> baz = Optional.empty();
}
then another error raised:
Caused by: java.lang.IllegalArgumentException: type=class java.util.Optional is unsupported, it must either be of type Marshallable, String or AutoBoxed primitive Object
at net.openhft.chronicle.wire.ValueOut.object(ValueOut.java:682)
at net.openhft.chronicle.wire.ValueOut.untypedObject(ValueOut.java:795)
at net.openhft.chronicle.wire.ValueOut.object(ValueOut.java:519)
at net.openhft.chronicle.wire.WireMarshaller$ObjectFieldAccess.getValue(WireMarshaller.java:669)
at net.openhft.chronicle.wire.WireMarshaller$FieldAccess.write(WireMarshaller.java:518)
at net.openhft.chronicle.wire.WireMarshaller.writeMarshallable(WireMarshaller.java:199)
at net.openhft.chronicle.wire.Marshallable.writeMarshallable(Marshallable.java:132)
I did not give up and tried to implement my own optional. Here it's:
#AllArgsConstructor(staticName = "of")
#NoArgsConstructor(staticName = "empty")
public class OptionalValue<T extends Marshallable> implements Marshallable {
#Nullable
private T value;
#Override
public void readMarshallable(#NotNull WireIn wire) throws IORuntimeException {
var val = wire.read("value");
if (!val.isNull()) {
val.marshallable(value);
}
}
#Override
public void writeMarshallable(#NotNull WireOut wire) {
if (value == null) {
wire.write("value").nu11();
} else {
wire.write("value").marshallable(value);
}
}
boolean isEmpty() { return value == null; }
T get() { return value; }
}
In this case, I saw another error:
Caused by: java.lang.ClassCastException
at net.openhft.chronicle.core.util.ObjectUtils.asCCE(ObjectUtils.java:294)
at net.openhft.chronicle.core.util.ObjectUtils$ConversionFunction.apply(ObjectUtils.java:624)
at net.openhft.chronicle.core.util.ObjectUtils$ConversionFunction.apply(ObjectUtils.java:592)
at net.openhft.chronicle.core.ClassLocal.computeValue(ClassLocal.java:54)
at java.base/java.lang.ClassValue.getFromHashMap(ClassValue.java:226)
at java.base/java.lang.ClassValue.getFromBackup(ClassValue.java:208)
at java.base/java.lang.ClassValue.get(ClassValue.java:114)
at net.openhft.chronicle.core.util.ObjectUtils.convertTo0(ObjectUtils.java:257)
... 28 more
Caused by: java.lang.NoSuchMethodException: com.redacted.entity.OptionalValue.<init>(java.lang.String)
Caused by: java.lang.NoSuchMethodException: com.redacted.entity.OptionalValue.<init>(java.lang.String)
at java.base/java.lang.Class.getConstructor0(Class.java:3349)
at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2553)
at net.openhft.chronicle.core.util.ObjectUtils$ConversionFunction.apply(ObjectUtils.java:620)
So does anybody know how to fix or use it properly?
ChronicleWire 2.22ae6

As SelfDescribingMarshallable is BytesMarsahallable, Map prefers to use this lower level serialization. However, because it is so low level, it doesn't support null values.
You can tell the builder to use Marshallable by setting the valueMarshaller
.valueMarshaller(new MarshallableReaderWriter<>(Foo.class))

Related

How to inject a service with multiples implementations with Net6

Hello i am trying to inject dependency of service with multiples implementations (multiple classes that implement the IDBActionQuery interface). I have this code in my Program.cs
builder.Services.AddTransient<IDBActionQuery<Period>, Select<Period>>();
And i have this interface:
public interface IDBActionQuery<T>
{
Task<List<T>> execute(string query, params (string name, object val)[] pars);
Task<List<T>> buildAndExecute();
}
And this is my Select class:
public class Select<T> : DBMotorBase<T>, IDBActionQuery<T>
{
private readonly IPrintExceptions exceptions;
private readonly IGetPropertiesService propertiesService;
private readonly ISQLParametersService sqlParameterService;
private readonly ISerializeService serializeService;
private readonly IDeserealizeService<T> deserealizeService;
public Select(string _connection,
IPrintExceptions _exceptions, IGetPropertiesService _propertiesService,
ISQLParametersService _sqlParameterService, ISerializeService _serializeService,
IDeserealizeService<T> _deserealizeService) : base(_connection)
{
exceptions = _exceptions;
propertiesService = _propertiesService;
sqlParameterService = _sqlParameterService;
serializeService = _serializeService;
deserealizeService = _deserealizeService;
}
private string build(string schema = "dbo")
{
...
}
public async Task<List<T>> buildAndExecute()
{
return await execute(build(),null);
}
public async Task<List<T>> execute(string query, params (string name, object val)[] pars)
{
...
}
private async Task<List<T>> processCommand(SqlConnection sql,
string query, params (string name, object val)[] pars)
{
...
}
private async Task<List<T>> processReader(SqlCommand cmd)
{
....
}
}
However i am receiving this error:
Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType:
Why is that???
The constructor of Select<T> should only contain Classes/Interfaces that can be injected. To do that, they must be registered as services like you did with Select<T>.
This is why it's throwing the Some services are not able to be constructed. It can't resolve the services you specified in the constructor. It can't create a fitting instance.
Guessing from your code, the problem is "string _connection". Try injecting "string _connection" via the e.g. IConfiguration or IOptions pattern instead. (Of course the other constructor parameters need to be registered services too!)
Something like this:
appsettings.json:
"ConnectionOptions": {
"Connection": "..."
},
Program.cs:
builder.Services.Configure<ConnectionOptions>
(builder.Configuration.GetSection(nameof(ConnectionOptions)));
Select<T>:
public Select(IOptions<ConnectionOptions> options,
IPrintExceptions exceptions,
IGetPropertiesService propertiesService,
ISQLParametersService sqlParameterService,
ISerializeService serializeService,
IDeserealizeService<T> deserealizeService)
: base(options.Connection)
{
_exceptions = exceptions;
_propertiesService = propertiesService;
_sqlParameterService = sqlParameterService;
_serializeService = serializeService;
_deserealizeService = deserealizeService;
}
If the "string _connection" property is a regular db connection string, I'd use IConfiguration instead.
Check out this question and similar ones for some detailed explanations.

How to use #ConfigProperties with a Converter class

I tried to implement a custom config type and it worked. However, when I use the custom type with a group of config using the #ConfigProperties it fails to automatically recognize the property by its name and instead treats the property as an object with a nested property.
How can I implement such a behavior correctly? (I am new to Quarkus, so please correct me if I am doing something wrong here)
Here is a code snippet that converts a custom type:
public class Percentage {
private double percentage;
public Percentage() {}
public Percentage(double percentage) {
this.percentage = percentage;
}
public void setPercentage(double percentage) {
this.percentage = percentage;
}
public double getPercentage() {
return this.percentage;
}
}
#Priority(300)
public class PercentageConverter implements Converter<Percentage> {
#Override
public Percentage convert(String value) {
int percentIndex = value.indexOf("%");
return new Percentage(Double.parseDouble(value.substring(0, percentIndex - 1)));
}
}
/// this works ------
public class Hello {
#ConfigProperty(name = "custom.vat")
Percentage vat;
public Hello () {
}
// .....
}
/// however, this fails
#ConfigProperties(prefix = "custom")
public class CustomConfig {
public Percentage vat;
public Percentage profit;
}
javax.enterprise.inject.spi.DeploymentException: No config value of type [double] exists for: custom.vat.percentage
at io.quarkus.arc.runtime.ConfigRecorder.validateConfigProperties(ConfigRecorder.java:39)
Unfortunately, I believe this does not work because Quarkus #ConfigProperties, handles these cases as if they were subgroups and try to map nested properties with the configuration (and not use the Converter).
Feel free to open up an issue in Quarkus GH if you feel this should change: https://github.com/quarkusio/quarkus/issues
Alternately, you can use SR Config #ConfigMapping: https://smallrye.io/docs/smallrye-config/mapping/mapping.html. It covers a few more cases, including direct Conversion and in the future it may replace Quarkus #ConfigProperties.

Spring data neo4j embedded property MappingException

I am fairly new to Neo4J; I am developing a project for learning purposes on which I am facing an issue that I am not managing to solve. My model might be somewhat relational DB influenced, but design issues aside, I believe however that what I am attempting should technically be done.
I have a NodeEntity Foo with an nested object Bar, converted to- and from String via ConversionService. In effect, Bar contains only one single String field, making the mapping trivial.
#NodeEntity
public class Foo {
#GraphId
private Long id;
#Indexed
private Bar bar;
...
}
public class Bar {
private String value;
...
}
When returning from a fairly simple Cypher query defined as follows on my repository:
#RepositoryRestResource(...)
public interface FooRepository
extends PagingAndSortingRepository<Foo, Long> {
...
#Query ("MATCH (foo) RETURN foo.bar")
Iterable<Bar> listBars ();
...
}
Conversion is configured as follows:
#Configuration
#ComponentScan(value = "de.h7r.playground.sd.neo4j",
excludeFilters = #ComponentScan.Filter({ Configuration.class }))
public class PKanbanConfiguration {
#Bean
public ConversionServiceFactoryBean conversionService ()
throws Exception {
final ConversionServiceFactoryBean csfb = new ConversionServiceFactoryBean ();
csfb.setConverters (getConverters ());
return csfb;
}
private Set<Converter> getConverters () {
return Sets.newHashSet (new BarConverter.ToString (), new BarConverter.FromString ());
}
}
Where the code for BarConverter is as follows.
public class BarConverter {
public static class FromString <S extends String, P extends Bar>
implements Converter<S, P> {
#Override
public P convert (final S source) {
// sets value into new instance of Bar and returns
}
}
public static class ToString <P extends Bar, S extends String>
implements Converter<P, S> {
#Override
public S convert (final P source) {
// gets value from Bar and returns
}
}
}
I am getting the following exception.
org.springframework.data.mapping.model.MappingException: Unknown persistent entity test.domain.Bar
at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:178)
...
Bar is indeed not a persitent entity nor should in my understanding be one. I grasp that this might have something to do with the defined return type of listBars; on the other hand, the repository if of Foos, so I had expected it to work. I would very much not like to fetch the whole set of nodes and then filter only the nested objects; the same way I would not like to have Bar replaced by String on Foo, since their type might have semantic relevance.
I am a bit lost as to how to returning all the property values for the existing nodes, specially since this query works as expected from neo4j-shell, so I see this as a pure Spring mapping issue.
I can add any further information that might prove helpful upon request.
Any help is very much appreciated.

NullPointerException in EnumMap when auto generating wadl with Jersey

I am using Tomcat 7, Jaxb2 and Jersey1.11.
I have a class EnumProperty which inherits from an abstract class Property.
#XmlAccessorType(XmlAccessType.FIELD)
public class EnumProperty extends Property<Enum> {
#XmlElement(name = "property_value", nillable = true)
private Enum value;
public EnumProperty() {
setValueType(PropertyValueTypeEnum.ENUM);
}
#Override
public Enum getValue() {
return value;
}
#Override
public void setValue(Enum value) {
this.value = value;
}
}
There are other sub classes for the Property class. In addition, I have another class, Entity, which holds a collection of properties. I have also a resource which returns in one of its sub resources a Collection. When I try to generate my application wadl I receive a NullPointerException. I isolated the problem to the EnumProperty class. Can anyone please help me understand where the problem is?
java.lang.NullPointerException
java.util.EnumMap.<init>(Unknown Source)
com.sun.xml.bind.v2.model.impl.RuntimeEnumLeafInfoImpl.<init>(RuntimeEnumLeafInfoImpl.java:87)
com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.createEnumLeafInfo(RuntimeModelBuilder.java:109)
com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.createEnumLeafInfo(RuntimeModelBuilder.java:85)
com.sun.xml.bind.v2.model.impl.ModelBuilder.getClassInfo(ModelBuilder.java:228)
com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:104)
com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:85)
com.sun.xml.bind.v2.model.impl.ModelBuilder.getClassInfo(ModelBuilder.java:213)
com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:99)
com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:85)
com.sun.xml.bind.v2.model.impl.ModelBuilder.getTypeInfo(ModelBuilder.java:319)
com.sun.xml.bind.v2.model.impl.TypeRefImpl.calcRef(TypeRefImpl.java:96)
com.sun.xml.bind.v2.model.impl.TypeRefImpl.getTarget(TypeRefImpl.java:73)
com.sun.xml.bind.v2.model.impl.RuntimeTypeRefImpl.getTarget(RuntimeTypeRefImpl.java:62)
com.sun.xml.bind.v2.model.impl.RuntimeTypeRefImpl.getTarget(RuntimeTypeRefImpl.java:55)
com.sun.xml.bind.v2.model.impl.ElementPropertyInfoImpl$1.get(ElementPropertyInfoImpl.java:78)
com.sun.xml.bind.v2.model.impl.ElementPropertyInfoImpl$1.get(ElementPropertyInfoImpl.java:81)
java.util.AbstractList$Itr.next(Unknown Source)...

Spring - Qualify injection candidates by designated environment

Edit:
Perhaps a more concise way to ask this question is: Does Spring provide a way for me to resolve ambiguous candidates at injection time by providing my own listener/factory/decision logic?
In fact, arguably the #Environmental qualifier on the member field below is unnecessary: if an #Inject-ion is ambiguous... let me help? In fact, #ResolveWith(EnvironmentalResolver.class) would be alright too..
When Spring attempts to inject a dependency (using annotations) I understand that I need to #Qualifier an #Inject point if I am to have multiple components that implement that interface.
What I'd like to do is something like this:
class MyFoo implements Foo {
#Inject
#Environmental
private Bar bar;
}
#Environmental(Environment.Production)
class ProductionBar implements Bar {
}
#Environmental({Environment.Dev, Environment.Test})
class DevAndTestBar implements Bar {
}
I would expect that I need to create some kind of ambiguity resolver which would look something (vaguely) like this:
class EnvironmentalBeanAmbiguityResolver {
// set from configuration, read as a system environment variable, etc.
private Environment currentEnvironment;
public boolean canResolve(Object beanDefinition) {
// true if definition has the #Environmental annotation on it
}
public Object resolve(Collection<Object> beans) {
for (Object bean : beans) {
// return bean if bean #Environmental.values[] contains currentEnvironment
}
throw new RuntimeException(...);
}
}
One example of where this would be useful is we have a service that contacts end-users. Right now I just have a hacked together AOP aspect that before the method call to the "MailSender', checks for a "Production" environment flag and if it is not set, it sends the email to us instead of the users email. I'd like to instead of wrapping this in an AOP aspect specific to mail sending, instead be able to differentiate services based on the current environment. Sometime's it is just a matter of "production" or "not production" as I've demonstrated above, but a per-environment definition works too.
I think this can be reused for region too... e.g. #Regional and #Regional(Region.UnitedStates) and so on and so forth.
I'd imagine #Environmental would actually be a #Qualifier that way if you wanted to depend directly on something environmental you could (an #Environmental(Production) bean would likely depend directly on an #Environmental(Production) collaborator - so no ambiguity for lower level items --- same a #Regional(US) item would depend on other #Regional(US) items expiclitly and would bypass my yet-to-be-understood BeanAmbiguityResolver)
Thanks.
I think I solved this!
Consider the following:
public interface Ambiguity {
public boolean isSatisfiedBy(BeanDefinitionHolder holder);
}
#Target({ METHOD, CONSTRUCTOR, FIELD })
#Retention(RUNTIME)
public #interface Ambiguous {
Class<? extends Ambiguity> value();
}
#Target(TYPE)
#Retention(RUNTIME)
public #interface Environmental {
public static enum Environment {
Development, Testing, Production
};
Environment[] value() default {};
}
#Named
public class EnvironmentalAmbiguity implements Ambiguity {
/* This can be set via a property in applicationContext.xml, which Spring
can use place holder, environment variable, etc. */
Environment env = Environment.Development;
#Override
public boolean isSatisfiedBy(BeanDefinitionHolder holder) {
BeanDefinition bd = holder.getBeanDefinition();
RootBeanDefinition rbd = (RootBeanDefinition) bd;
Class<?> bc = rbd.getBeanClass();
Environmental env = bc.getAnnotation(Environmental.class);
return (env == null) ? false : hasCorrectValue(env);
}
private boolean hasCorrectValue(Environmental e) {
for (Environment env : e.value()) {
if (env.equals(this.env)) {
return true;
}
}
return false;
}
}
#Named
public class MySuperDuperBeanFactoryPostProcessor implements
BeanFactoryPostProcessor, AutowireCandidateResolver {
private DefaultListableBeanFactory beanFactory;
private AutowireCandidateResolver defaultResolver;
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg)
throws BeansException {
if (arg instanceof DefaultListableBeanFactory) {
beanFactory = (DefaultListableBeanFactory) arg;
defaultResolver = beanFactory.getAutowireCandidateResolver();
beanFactory.setAutowireCandidateResolver(this);
return;
}
throw new FatalBeanException(
"BeanFactory was not a DefaultListableBeanFactory");
}
#Override
public Object getSuggestedValue(DependencyDescriptor descriptor) {
return defaultResolver.getSuggestedValue(descriptor);
}
#Override
public boolean isAutowireCandidate(BeanDefinitionHolder holder,
DependencyDescriptor descriptor) {
Ambiguity ambiguity = getAmbiguity(descriptor);
if (ambiguity == null) {
return defaultResolver.isAutowireCandidate(holder, descriptor);
}
return ambiguity.isSatisfiedBy(holder);
}
private Ambiguity getAmbiguity(DependencyDescriptor descriptor) {
Ambiguous ambiguous = getAmbiguousAnnotation(descriptor);
if (ambiguous == null) {
return null;
}
Class<? extends Ambiguity> ambiguityClass = ambiguous.value();
return beanFactory.getBean(ambiguityClass);
}
private Ambiguous getAmbiguousAnnotation(DependencyDescriptor descriptor) {
Field field = descriptor.getField();
if (field == null) {
MethodParameter methodParameter = descriptor.getMethodParameter();
if (methodParameter == null) {
return null;
}
return methodParameter.getParameterAnnotation(Ambiguous.class);
}
return field.getAnnotation(Ambiguous.class);
}
}
Now if I have an interface MyInterface and two classes that implement it MyFooInterface and MyBarInterface like this:
public interface MyInterface {
public String getMessage();
}
#Named
#Environmental({ Environment.Testing, Environment.Production })
public class MyTestProdInterface implements MyInterface {
#Override
public String getMessage() {
return "I don't always test my code, but when I do, I do it in production!";
}
}
#Named
#Environmental(Environment.Development)
public class DevelopmentMyInterface implements MyInterface {
#Override
public String getMessage() {
return "Developers, developers, developers, developers!";
}
}
If I want to #Inject MyInterface I would get the same multiple bean definition error that one would expect. But I can add #Ambiguous(EnvironmentalAmbiguity.class) and then the EnvironmentalAmbiguity will tell which bean definition it is satisfied by.
Another approach would have been to use a List and go through them all seeing if they are satisfied by a given bean definition, this would mean that the dependnecy wouldn't need the #Ambiguous annotation. That might be more "IoC-ish" but I also thought it might perform poorly. I have not tested that.

Resources