On Friday, March 17, 2017 at 11:36:18 AM UTC+2, Lukas Eder wrote:
>
> Hi Oded,
>
> Thanks for your message. We're aware that the version 3.0 of our code 
> generator lacks the extension capabilities that many users desire, and we 
> definitely will improve it heavily in version 4.0.
>
 
That would be great. I often use ORM libraries that allow me to write the 
business logic "close to the data". The current implementation of Jooq is 
not really suitable to ORM style business logic - its just OO data access, 
which I think is a shame - it forces the user to manage another set of 
objects for business logic.

  

> Ideally I would have liked to just override the `pType` inside 
>> `generateDao()`, but there's no extension point for that and the likely 
>> candidate - 
>>
>
> I'm not sure if that's the right candidate. It will map to the generated 
> POJO class, whereas you'd like it to return a subtype. But returning a 
> subtype might break a lot of assumptions that are made throughout the code 
> generator, so this might not be the right place after all.
>

Well, I need the DAO to generate my subtypes when it creates new record 
instances, otherwise I can't expose business logic through the record type. 
I don't mind the DAO using the base POJO type in method definitions, as my 
subtype is assignable. 

looking at DAOImpl now, I can see that I just need to overwrite the POJO 
type generated into the DAO constructor code. Unfortunately - again, no 
extensability, so there's no way to replace just that without overwrite the 
entire `generateDao()` method or hacking away just at `pType`.

 

>  `AbstractGeneratorStrategy.getFullJavaClassName()` is final and cannot be 
> overridden (why a final in an abstract class?!?).
>
> To protect the assumptions that are otherwise made in the code generator.
>

I feel that there is likely a way to protect assumptions by documenting 
them well and putting in checking code that will cause the build or library 
initialization to throw exceptions when assumptions are breached, but I 
have no concrete knowledge so I'm probably mistaken here.
 

My solution was to override the `JavaWriter` class and add a text level 
>> processor. Its not a good solution, but between Wrong Thing A and Wrong 
>> Thing B, I chose the one that is easier to understand, maintain and detect 
>> the error when it breaks.
>>
>
>
> I'm willing to share the implementation if anyone is interested.
>>
>
> Would be interesting to look at, definitely! Thanks for the offer.
>

Please see attached. This is not based directly on the Jooq JavaGenerator, 
instead I'm using the https://github.com/jklingsporn/vertx-jooq 
VertxGenerator so I'm sub-typing that - but the code should be easily 
adaptable to use JavaGenerator directly and the magic is all in the 
`OverridableJavaWriter` anyway. The JavaWriter sub-type just uses string 
searches (yuck, I know) to identify the original POJO type name and replace 
it with a matching "concrete type" if such exists in the configured 
"concrete implementation package". 

The main problem I had was that some well behaving generators use the type 
name as an argument to `JavaWriter.println()` which allows me to do a 
direct string match and be happy, while others - notably `VertxGenerator` 
like to use `String.format()` to embed the type name in large strings that 
are then passed to `JavaWriter.println()` as the first argument - forcing 
me to do string searches...

-- 
You received this message because you are subscribed to the Google Groups "jOOQ 
User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.
package il.co.gftc.jooq;

import java.io.File;
import java.time.Instant;

import org.jooq.util.*;

import io.github.jklingsporn.vertx.impl.*;

public class CustomGenerator extends VertxGenerator {

	@Override
	protected void generateDao(TableDefinition table, JavaWriter out) {
		((OverridableJavaWriter) out).setTable(table, getStrategy());
		super.generateDao(table, out);
	}

	@Override
	protected JavaWriter newJavaWriter(File file) {
		return new OverridableJavaWriter(file, generateFullyQualifiedTypes(), targetEncoding);
	}

}
package il.co.gftc.jooq;

import java.io.File;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import org.jooq.util.GeneratorStrategy;
import org.jooq.util.TableDefinition;
import org.jooq.util.GeneratorStrategy.Mode;
import org.jooq.util.JavaWriter;

import io.github.jklingsporn.vertx.impl.VertxJavaWriter;

public class OverridableJavaWriter extends VertxJavaWriter {

	private String m_sourceType;
	private String m_targetType;

	public OverridableJavaWriter(File file, String generateFullyQualifiedTypes, String targetEncoding) {
		super(file, generateFullyQualifiedTypes, targetEncoding);
	}

	public void setTable(TableDefinition table, GeneratorStrategy st) {
		String pojoPkg = st.getJavaPackageName(table, Mode.POJO);
		m_sourceType = st.getFullJavaClassName(table, Mode.POJO);
		m_targetType = m_sourceType.replace(pojoPkg, getImplPkg(pojoPkg));
		File targetFile = new File(st.getTargetDirectory() + "/" + m_targetType.replace('.', '/') + ".java");
		if (!targetFile.exists())
			m_targetType = null;
	}

	private String getImplPkg(String originalPojoPkg) {
		return System.getProperty("il.co.gftc.jooq.concrete-package", originalPojoPkg + ".concrete");
	}

	@Override
	public String ref(String clazzOrId) {
		if (Objects.equals(m_sourceType, clazzOrId) && Objects.nonNull(m_targetType))
			return super.ref(m_targetType);
		return super.ref(clazzOrId);
	}

	@Override
	protected List<String> ref(List<String> clazzOrIds) {
		return super.ref(Objects.isNull(clazzOrIds) ? null
				: clazzOrIds.stream()
						.map(s -> Objects.equals(m_sourceType, s) && Objects.nonNull(m_targetType) ? m_targetType : s)
						.collect(Collectors.toList()));
	}

	@Override
	public JavaWriter print(String string, Object... args) {
		return super.print(replaceInText(string), replaceInArray(args));
	}

	private Object[] replaceInArray(Object[] args) {
		for (int i = 0; i < args.length; i++)
			if (args[i] instanceof String)
				args[i] = replaceInText((String) args[i]);
			else if (args[i] instanceof Collection) {
				args[i] = replaceInArray(((Collection<?>) args[i]).toArray());
			}
		return args;
	}

	private String replaceInText(String string) {
		if (Objects.isNull(m_targetType))
			return string;
		if (!string.contains(m_sourceType))
			return string;
		System.err.println("Replacing " + m_sourceType + " with " + m_targetType + " in '" + string + "'");
		return string.replaceAll(m_sourceType.replaceAll("\\.", "\\\\."), m_targetType);
	}
}

Reply via email to