I see that you are factoring out the resolution logic by introducing the notion of ActionType and reusing the same call tree for resolving types, converters and writers.
However the notion of ActionType and interleaving of those logics makes it hard to read when you can decouple the resolution logic from the actual creation of converters/types/writers.
I would like to suggest the following improvement to this class.
Define a Resolver type which will represent the result of the resolution by creating a tree of resolvers based on the input class. There will be several implementation of resolver for primitive/object/array etc. This will contain all the resolution and data needed to actually produce converters/types/writers.
On the root resolver add getConverter(), getType(), getWriter() that know how to create those objects by delegating to the children for nested objects.
I use a similar idea in the io package: https://github.com/Parquet/parquet-mr/blob/ce2301e2c663a2944d9ca1ea6349d55074bf70f9/parquet-column/src/main/java/parquet/io/ColumnIOFactory.java#L139
(you don't need a visitor, but that's the idea)
What do you think?