question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Allow instancing of classes with non-empty constructor

See original GitHub issue

Is your feature request related to a problem? Please describe. Kotlin data classes (even of embedded objects) must have initatizers for their values:

This works fine

data class My class(val value : Int = 0)

However, this does not

data class My class(val value : Int)

The problem lies in the instance creator which always tries to find a parameterless constructor to instanciate the classes with. If this is missing morphia throws an error.

Mappers like Gson and Jackson have work arounds for this. Morphia should be able to do the same.

Consider adding this great class to the instance creator of no suitable constructor is found:

https://github.com/google/gson/blob/master/gson/src/main/java/com/google/gson/internal/UnsafeAllocator.java

Another solution could be to fetch the constructor with the least number or parameters and try to insert their default values if primitives or use it recursively if not. I have a PoC for this which works great. Here it is

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Map;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toMap;

public class ConstructorlessInstance {

    private static final Map<Class<?>, Object> DEFAULT_VALUES = Stream
            .of(boolean.class, byte.class, char.class, double.class, float.class, int.class, long.class, short.class)
            .collect(toMap(clazz -> (Class<?>) clazz, clazz -> Array.get(Array.newInstance(clazz, 1), 0)));


    public static <T> T create(final Class<? super T> rawType) throws IllegalAccessException, InvocationTargetException, InstantiationException {

        var constructor = Arrays.stream(rawType.getDeclaredConstructors()).min(Comparator.comparingInt(Constructor::getParameterCount)).orElseGet(() -> {
            throw new IllegalStateException("Found no constructors");
        });
        var arguments = new Object[constructor.getParameterCount()];
        createDefaultArguments(arguments, constructor.getParameters());
        constructor.setAccessible(true);

        //noinspection unchecked
        return (T) constructor.newInstance(arguments);
    }

    private static void createDefaultArguments(Object[] arguments, Parameter[] parameters) throws IllegalAccessException, InvocationTargetException, InstantiationException {
        for (int i = 0; i < parameters.length; i++) {
            arguments[i] = createDefaultArgument(parameters[i]);
        }
    }

    private static Object createDefaultArgument(Parameter parameter) throws IllegalAccessException, InstantiationException, InvocationTargetException {
        var type = parameter.getType();
        if (type.isPrimitive()) {
            return DEFAULT_VALUES.get(type);
        }

        if (type.isAssignableFrom(String.class)) {
            return "";
        }

        return create(type);
    }
}

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:7 (7 by maintainers)

github_iconTop GitHub Comments

2reactions
evanchoolycommented, May 1, 2020

I thought i had an issue open for this already. It’s often on my mind anyway. This is a priority issue for me, personally.

1reaction
evanchoolycommented, Oct 31, 2020

@Constructor is no longer required (or even used) and @Name annotations are optional now and only needed when the constructor argument name does not match the field name. Of course, for data classes those are one and the same. Details will be up on the morphia.dev website once the docs sync completes in about 20 minutes.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to autowire a class with non-empty constructor?
To address a comment you made to another answer, you can create a List bean in XML as shown in the Spring docs....
Read more >
Code Inspection: Empty constructor - ReSharper - JetBrains
Having an empty constructor (whether static or not) in a class is redundant, and ReSharper issues a warning to that effect.
Read more >
Default constructors - cppreference.com
A default constructor is a constructor which can be called with no arguments (either defined with an empty parameter list, or with default ......
Read more >
Classes - JavaScript - MDN Web Docs
Classes are a template for creating objects. They encapsulate data with code to work on that data. Classes in JS are built on...
Read more >
Using Constructors - C# Programming Guide | Microsoft Learn
When a class or struct is instantiated, its constructor is called. ... by the C# compiler in order to enable class instantiation.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found