Internal or external?
I think Java is just fine for internal DSLs, see
https://www.jooq.org/
jooq embeds a Turing complete programming language because it supports Procedural SQL.
I was also hacking on this project
https://github.com/paulhoule/ferocity/
which was about making Java homoiconic. Namely in ferocity you can write
Expression<String> literal = of("Hello World");
Expression<byte[]> expression = getBytes(literal);
and then
expression.asSource() = '"Hello World".getBytes()'
expression.evaluate() = {72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100}
the evaluation is done with the primitive interpreter strategy of evaluating all of the arguments of the function then calling the function, ...
I got far enough on that project that I discovered a bunch of things like the expression language has extensions over the real Java language pretty naturally for instance if you have a quote function like the quote in LISP you can write programs in the extended language to process syntactic macros.
I convinced myself that the idea is sound and got started on bootstrapping it by building a partial implementation (ferocity0) and code generator to make stubs out of the standard library plus a persistent collections library because that is pretty helpful for building the DSL, then write ferocity1 in ferocity0 wherever it could eliminate boilerplate (like the 8 primitive types.)