The ability to abstract is one of the most powerful tools of the human brain. It allows it to handle complex systems as simple entities, provided the abstractions it works with are suitable.
This concept is very often applied to programming, because inevitably, we have to handle complex systems. Even Java as a language is already an abstraction of the JVM, which in turn is an abstraction of the actual machine you are running on. SQL is an abstraction of relational databases, which in turn are an abstraction of storage.
All this works well, because you think in terms of concepts in one abstraction layer, and this layer is separated from the layers below through an abstraction barrier. This is very well explained in SICP.
Based on this is the rather common approach of abstracting architecture and infrastructure. Libraries that do that are commonly referred to as frameworks (although nowadays everything is referred to as a framework).
One thing you will have to accept with frameworks is, that you must think within the abstraction layer they provide. How they work internally is none of your concern (assuming they work as specified) except for personal curiosity.
It is important to understand what a software component does, not how. In fact relying on the how is a good way of shooting yourself in the foot. Standing on the shoulders of giants is good.
Now to come back to code generators: Code generators are in a way an instrument of abstraction. You say: I want a controller for this and that, and zooooom it's there. You don't have to think about how it ties into the rest of the infrastructure, because all that is abstracted away. This is good.
However, I earlier mentioned the concept of abstraction barriers. An inherent problem of code generators is they provide no abstraction barrier. All the stuff they need, they do not hide it from you, but instead they throw it in your face. And you have code that consists of parts that you must change and parts that you mustn't change (as long as you want to stay in the same abstraction layer).
In some languages, Java being the canonical example, code generators are inevitable if you want to reach certain levels of abstraction. But as long as you have a clear understanding what the purpose of the code is that you generate and know which parts not to touch, you're on the safe side.