Suppose you have this protobuf model:
message ComplexKey {
string name = 1;
int32 domainId = 2;
}
message KeyMsg {
oneof KeyMsgOneOf {
string name = 1;
ComplexKey complexName= 2;
}
}
and an object obj, that you know is either a string or a ComplexKey.
Question
Whitout explicitly checking the obj class type, which is the most efficient way to build a new KeyMsg instance with the obj placed in the correct field using the protobuf Java API?
UPDATE: it would be great if protoc generates an helper method to do what I need.
UPDATE2: given the correct comment from Mark G. below and supposing that all fields differ in type, the best solution I've find so far is (simplified version):
List<FieldDescriptor> lfd = oneOfFieldDescriptor.getFields();
for (FieldDescriptor fieldDescriptor : lfd) {
if (fieldDescriptor.getDefaultValue().getClass() == oVal.getClass()) {
vmVal = ValueMsg.newBuilder().setField(fieldDescriptor, oVal).build();
break;
}
}
You can use switch-case:
public Object demo() {
KeyMsg keyMsg = KeyMsg.newBuilder().build();
final KeyMsg.KeyMsgOneOfCase oneOfCase = keyMsg.getKeyMsgOneOfCase();
switch (oneOfCase) {
case NAME: return keyMsg.getName();
case COMPLEX_NAME: return keyMsg.getComplexName();
case KEY_MSG_ONE_OF_NOT_SET: return null;
}
}
I doubt there is a better way than using instanceof:
KeyMsg.Builder builder = KeyMsg.newBuilder();
if (obj instanceof String) {
builder.setName((String) obj);
} else if (obj instanceof ComplexKey) {
builder.setComplexName((ComplexKey) obj);
} else {
throw new AssertionError("Not a String or ComplexKey");
}
KeyMsg msg = builder.build();
Related
I'm using the CSS Parser to get specific CSS rules that belong to a set HTML class. At the moment I have got a list of CSS rules in the site, however I cannot figure out how to get the rules I'm looking for.
Current Code:
InputSource inputSource = new InputSource("example.com");
CSSOMParser parser = new CSSOMParser(new SACParserCSS3());
ErrorHandler errorHandler = new CSSErrorHandler();
parser.setErrorHandler(errorHandler);
CSSStyleSheet sheet = parser.parseStyleSheet(inputSource, null, null);
CSSRuleList rules = sheet.getCssRules();
One of my options would be doing a for loop, but I'm reluctant to do this because
a. It will be slow if there is hundreds of rules in a page.
b. There appears to be no method to get the class name of a rule.
Any help would be appreciated
Add a: The CSS has already been parsed by your code, so you only have to look at the selectors which might be acceptable in terms of performance.
Add b: The CSSStyleRule interface lacks a method getSelectors() but CSSStyleRuleImpl has it. So you could try something along:
scanRules(rules, name -> name.contains("e"),
(names, rule) -> System.out.println(
new TreeSet<>(names) + " --> " + rule.getCssText()));
with recursive helper methods
// scan CSS rules including rules contained in media rules
void scanRules(CSSRuleList rules, Predicate<String> classNameTest,
BiConsumer<Set<String>, CSSStyleRule> ruleAction) {
for (int ri = 0; ri < rules.getLength(); ri++) {
CSSRule rule = rules.item(ri);
if (rule.getType() == CSSRule.MEDIA_RULE) {
CSSMediaRule mr = (CSSMediaRule) rule;
scanRules(mr.getCssRules(), classNameTest, ruleAction);
} else if (rule.getType() == CSSRule.STYLE_RULE) {
CSSStyleRuleImpl styleRule = (CSSStyleRuleImpl) rule;
SelectorList selectors = styleRule.getSelectors();
// if (!styleRule.getSelectorText().contains(".name"))
// continue; // selector text test might cause speed up...
for (int si = 0; si < selectors.getLength(); si++) {
Selector selector = selectors.item(si);
Set<String> classNames = classNamesInSelectorMatching(selector, classNameTest);
if (!classNames.isEmpty())
ruleAction.accept(classNames, styleRule);
}
}
}
}
// find matching class names in given (potentially complex) selector
Set<String> classNamesInSelectorMatching(Selector selector,
Predicate<String> nameMatches) {
switch (selector.getSelectorType()) {
case Selector.SAC_CHILD_SELECTOR:
case Selector.SAC_DESCENDANT_SELECTOR:
case Selector.SAC_DIRECT_ADJACENT_SELECTOR: {
DescendantSelector ds = (DescendantSelector) selector;
Set<String> set = new HashSet<>();
set.addAll(classNamesInSelectorMatching(ds.getAncestorSelector(), nameMatches));
set.addAll(classNamesInSelectorMatching(ds.getSimpleSelector(), nameMatches));
return set;
}
case Selector.SAC_NEGATIVE_SELECTOR: {
NegativeSelector ns = (NegativeSelector) selector;
return classNamesInSelectorMatching(ns.getSimpleSelector(), nameMatches);
}
case Selector.SAC_CONDITIONAL_SELECTOR: {
ConditionalSelector ns = (ConditionalSelector) selector;
return classNamesInConditionMatching(ns.getCondition(), nameMatches);
}
default:
return Collections.emptySet();
}
}
// find matching class names in given (potentially complex) condition
Set<String> classNamesInConditionMatching(Condition condition,
Predicate<String> nameMatches) {
switch (condition.getConditionType()) {
case Condition.SAC_CLASS_CONDITION: {
AttributeCondition ac = (AttributeCondition) condition;
if (nameMatches.test(ac.getValue()))
return Collections.singleton(ac.getValue());
else
return Collections.emptySet();
}
case Condition.SAC_AND_CONDITION:
case Condition.SAC_OR_CONDITION: {
CombinatorCondition cc = (CombinatorCondition) condition;
Set<String> set = new HashSet<>();
set.addAll(classNamesInConditionMatching(cc.getFirstCondition(), nameMatches));
set.addAll(classNamesInConditionMatching(cc.getSecondCondition(), nameMatches));
return set;
}
case Condition.SAC_NEGATIVE_CONDITION: {
NegativeCondition nc = (NegativeCondition) condition;
return classNamesInConditionMatching(nc.getCondition(), nameMatches);
}
default:
return Collections.emptySet();
}
}
I have tried it with input https://www.w3.org/2008/site/css/minimum-src.css and it seems to work for me.
How can I check if a selenium web element contains a specific css class.
I have this html li element
<li class="list-group-item ng-scope active" ng-repeat="report in lineageController.reports" ng-click="lineageController.activate(report)" ng-class="{active : lineageController.active == report}">
As you can see inside class attribute there is an active class.
My problem is that I have this element and I want to do a check based on if the class attribute has that "active" value among the others, being more elegant solution then using xpath.
How can I do this?
Given you already found your element and you want to check for a certain class inside the class-attribute:
public boolean hasClass(WebElement element) {
String classes = element.getAttribute("class");
for (String c : classes.split(" ")) {
if (c.equals(theClassYouAreSearching)) {
return true;
}
}
return false;
}
#EDIT
As #aurelius rightly pointed out, there is an even simpler way (that doesn't work very well):
public boolean elementHasClass(WebElement element, String active) {
return element.getAttribute("class").contains(active);
}
This approach looks simpler but has one big caveat:
As pointed out by #JuanMendes you will run into problems if the class-name you're searching for is a substring of other class-names:
for example class="test-a test-b", searching for class.contains("test") will return true but it should be false
#EDIT 2
Try combining the two code snippets:
public boolean elementHasClass(WebElement element, String active) {
return Arrays.asList(element.getAttribute("class").split(" ")).contains(active);
}
That should fix your caveat.
The answer provided by #drkthng works but you might have a case where the class name is a subset of another class name. For example:
<li class="list-group-item ng-scope active">text</li>
If you wanted to find the class "item" then the provided answer would give a false positive. You might want to try something like this:
public boolean hasClass(WebElement element, String htmlClass) {
String classes = element.getAttribute("class").split("\\s+");
if (classes != null) {
for (String classAttr: classes) {
if (classAttr.equals(htmlClass)) {
return true;
}
}
}
return false;
}
Use javascript: classList.contains
WebElement element = By.id("id");
String className = "hidden";
JavascriptExecutor js = (JavascriptExecutor) driver;
Boolean containsClass = js.executeScript("return arguments[0].classList.contains(arguments[1])", element, className);
Based on a common pre-classList javascript technique:
public boolean hasClass(WebElement element, String theClass) {
return (" " + element.getAttribute("class") + " ").contains(" " + theClass + " ");
}
Simmilar to previous one, but with java 8 capabilities:
String classes= getDriver().findElement(someSelector).getAttribute("class");
Optional<String> classFindResult = Arrays.stream(elementClasses.split(" ")).filter(el -> el.equals("myClass")).findFirst();
if(openClassFindResult.isPresent()){
return true;
}
return false;
Improving on #uesports135 answer, "classess" should be a String array.
public boolean hasClass(WebElement element, String htmlClass) {
String[] classes = element.getAttribute("class").split("\\s+");
if (classes != null) {
for (String classAttr: classes) {
if (classAttr.equals(htmlClass)) {
return true;
}
}
}
return false;
}
For anyone looking for a C# implementation:
public static class WebElementExtensions
{
private static Regex _classNameValidatorRegex = new Regex(#"^[a-z][a-z0-9\-_]*$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static Regex _whiteSpaceRegex = new Regex(#"\s+");
public static bool HasClass(this IWebElement element, params string[] htmlClasses)
{
if (!htmlClasses.Any())
throw new ArgumentException("No html classes to match.");
if (!htmlClasses.All(c => _classNameValidatorRegex.IsMatch(c)))
throw new ArgumentException("Invalid CSS class(es) detected.");
var classAttribute = element.GetAttribute("class");
if (string.IsNullOrWhiteSpace(classAttribute))
return false;
var elementClasses = _whiteSpaceRegex.Split(classAttribute.Trim()).ToHashSet();
return htmlClasses.All(c => elementClasses.Contains(c));
}
public static bool HasAnyClass(this IWebElement element, params string[] htmlClasses)
{
if (!htmlClasses.Any())
throw new ArgumentException("No html classes to match.");
if (!htmlClasses.All(c => _classNameValidatorRegex.IsMatch(c)))
throw new ArgumentException("Invalid CSS class(es) detected.");
var classAttribute = element.GetAttribute("class");
if (string.IsNullOrWhiteSpace(classAttribute))
return false;
var elementClasses = _whiteSpaceRegex.Split(classAttribute.Trim()).ToHashSet();
return htmlClasses.Any(c => elementClasses.Contains(c));
}
}
Try using contains();
String classes = divPubli.getAttribute("class");
assertTrue("The element does not contain .maClass class .publi",classes.contains("maClass"));
I have a set of JSONObject values which i receive from a server and operate on. Most times I get a JSONObject with a value (let's say statistics) and sometimes, it returns an Error object with a code and a description of the error.
How do I structure my code so that it doesn't break if it returns the error. I thought I could do this, but doesn't work.
public void processResult(JSONObject result) {
try {
if(result.getJSONObject(ERROR) != null ){
JSONObject error = result.getJSONObject(ERROR);
String error_detail = error.getString(DESCRIPTION);
if(!error_detail.equals(null)) {
//show error login here
}
finish();
}
else {
JSONObject info = result.getJSONObject(STATISTICS);
String stats = info.getString("production Stats"));
}
}
}
Use .has(String) and .isNull(String)
A conservative usage could be;
if (record.has("my_object_name") && !record.isNull("my_object_name")) {
// Do something with object.
}
It might be little late(it is for sure) but posting it for future readers
You can use JSONObject optJSONObject (String name) which will not throw any exception and
Returns the value mapped by name if it exists and is a JSONObject, or null otherwise.
so you can do
JSONObject obj = null;
if( (obj = result.optJSONObject("ERROR"))!=null ){
// it's an error , now you can fetch the error object values from obj
}
or if you just want to test nullity without fetching the value then
if( result.optJSONObject("ERROR")!=null ){
// error object found
}
There is whole family of opt functions which either return null or you can also use the overloaded version to make them return any pre-defined values.
e.g
String optString (String name, String fallback)
Returns the value mapped by name if it exists, coercing it if
necessary, or fallback if no such mapping exists.
where coercing mean, it will try to convert the value into String type
A modified version of the #TheMonkeyMan answer to eliminate redundant look-ups
public void processResult(JSONObject result) {
JSONObject obj = null;
if( (obj = result.optJSONObject("ERROR"))!=null ){
//^^^^ either assign null or jsonobject to obj
// if not null then found error object , execute if body
String error_detail = obj.optString("DESCRIPTION","Something went wrong");
//either show error message from server or default string as "Something went wrong"
finish(); // kill the current activity
}
else if( (obj = result.optJSONObject("STATISTICS"))!=null ){
String stats = obj.optString("Production Stats");
//Do something
}
else
{
throw new Exception("Could not parse JSON Object!");
}
}
In JSONObject there is a 'Has' method that you can do to Determaine the key.
I have no idea if this will work but it looks Credible.
public void processResult(JSONObject result) {
if(result.has("ERROR"))
{
JSONObject error = result.getJSONObject("ERROR")
String error_detail = error.getString("DESCRIPTION");
if(error_detail != null)
{
//Show Error Login
finish();
}
}
else if(result.has("STATISTICS"))
{
JSONObject info = result.getJSONObject("STATISTICS");
String stats = info.getString("Production Stats");
//Do something
}
else
{
throw new Exception("Could not parse JSON Object!");
}
}
It is sometimes more convenient and less ambiguous to have a NULL object than to use Java's null value.
JSONObject.NULL.equals(null) returns true.
JSONObject.NULL.toString()returns "null".
Example:
System.out.println(test.get("address").equals(null)); // Preferred way
System.out.println(test.getString("address").equals("null"));
source -- JSONObject oracle docs
Just a note:
With EE8 json specs, I can do an exception-safe get:
result.asJsonObject().getString("ERROR", null);
if, however, I want to do a check I can do it with:
result.asJsonObject().get("ERROR").equals(JsonValue.NULL)
If at any point in your code, org.json.JSONObject json_object becomes null and you wish to avoid NullPointerException (java.lang.NullPointerException), then do check it as below:
if(json_object == null) {
System.out.println("json_object is found as null");
}
else {
System.out.println("json_object is found as not null");
}
If in any case, your jsonobject is null.
Then use this statement for checking jsonobject is null or not.
if (!obj.get("data").isJsonNull()){
//Not Null
}else{
//Null
}
And for checking jsonobject is exist or not, use .has:
if (!obj.has("data")){
//Not Exist
}else{
//Exist
}
Assume there's an XMLBeans XmlObject with attributes, how can I get selected attributes in single step?
I'm expecting like something ....
removeAttributes(XmlObject obj, String[] selectableAttributes){};
Now the above method should return me the XMLObject with only those attributes.
Assumption: the attributes that you want to remove from your XmlObject must be optional in the corresponding XML Schema. Under this assumption, XMLBeans provides you with a couple of useful methods: unsetX and isSetX (where X is your attribute name. So, we can implement a removeAttributes method in this way:
public void removeAttributes(XmlObject obj,
String[] removeAttributeNames)
throws IllegalArgumentException, IllegalAccessException,
InvocationTargetException, SecurityException,
NoSuchMethodException {
Class<?> clazz = obj.getClass();
for (int i = 0; i < removeAttributeNames.length; i++) {
String attrName =
removeAttributeNames[i].substring(0, 1).toUpperCase() +
removeAttributeNames[i].substring(1);
String isSetMethodName = "isSet" + attrName;
Boolean isSet = null;
try {
Method isSetMethod = clazz.getMethod(isSetMethodName);
isSet = (Boolean) isSetMethod.invoke(obj, new Object[] {});
} catch (NoSuchMethodException e) {
System.out.println("attribute " + removeAttributeNames[i]
+ " is not optional");
}
if (isSet != null && isSet.booleanValue() == true) {
String unsetMethodName = "unset" + attrName;
Method unsetMethod = clazz.getMethod(unsetMethodName);
unsetMethod.invoke(obj, new Object[] {});
}
}
}
Note 1: I have slightly modified the semantics of your method signature: the second argument (the String[]) is actually the list of attributes that you want to remove. I think this is more consistent with the method name (removeAttributes), and it also simplify things (using unsetX and isSetX).
Note 2: The reason for calling isSetX before calling unsetX is that unsetX would throw an InvocationTargetException if called when the attribute X is not set.
Note 3: You may want to change exception handling according to your needs.
I think you can use a cursor ... they are cumbersome to handle, but so is reflection.
public static XmlObject RemoveAllAttributes(XmlObject xo) {
return RemoveAllofType(xo, TokenType.ATTR);
}
public static XmlObject RemoveAllofTypes(XmlObject xo, final TokenType... tts) {
printTokens(xo);
final XmlCursor xc = xo.newCursor();
while (TokenType.STARTDOC == xc.currentTokenType() || TokenType.START == xc.currentTokenType()) {
xc.toNextToken();
}
while (TokenType.ENDDOC != xc.currentTokenType() && TokenType.STARTDOC != xc.prevTokenType()) {
if (ArrayUtils.contains(tts, xc.currentTokenType())) {
xc.removeXml();
continue;
}
xc.toNextToken();
}
xc.dispose();
return xo;
}
I am using this simple method to clean everything in the element. You can omit the cursor.removeXmlContents to only delete attributes. Second cursor is used to return to the initial position:
public static void clearElement(final XmlObject object)
{
final XmlCursor cursor = object.newCursor();
cursor.removeXmlContents();
final XmlCursor start = object.newCursor();
while (cursor.toFirstAttribute())
{
cursor.removeXml();
cursor.toCursor(start);
}
start.dispose();
cursor.dispose();
}
I have tried to find information about this but have come up empty handed:
I gather it is possible to create a class dynamically in Java using reflection or proxies but I can't find out how. I'm implementing a simple database framework where I create the SQL queries using reflection. The method gets the object with the database fields as a parameter and creates the query based on that. But it would be very useful if I could also create the object itself dynamically so I wouldn't have the need to have a simple data wrapper object for each table.
The dynamic classes would only need simple fields (String, Integer, Double), e.g.
public class Data {
public Integer id;
public String name;
}
Is this possible and how would I do this?
EDIT: This is how I would use this:
/** Creates an SQL query for updating a row's values in the database.
*
* #param entity Table name.
* #param toUpdate Fields and values to update. All of the fields will be
* updated, so each field must have a meaningful value!
* #param idFields Fields used to identify the row(s).
* #param ids Id values for id fields. Values must be in the same order as
* the fields.
* #return
*/
#Override
public String updateItem(String entity, Object toUpdate, String[] idFields,
String[] ids) {
StringBuilder sb = new StringBuilder();
sb.append("UPDATE ");
sb.append(entity);
sb.append("SET ");
for (Field f: toUpdate.getClass().getDeclaredFields()) {
String fieldName = f.getName();
String value = new String();
sb.append(fieldName);
sb.append("=");
sb.append(formatValue(f));
sb.append(",");
}
/* Remove last comma */
sb.deleteCharAt(sb.toString().length()-1);
/* Add where clause */
sb.append(createWhereClause(idFields, ids));
return sb.toString();
}
/** Formats a value for an sql query.
*
* This function assumes that the field type is equivalent to the field
* in the database. In practice this means that this field support two
* types of fields: string (varchar) and numeric.
*
* A string type field will be escaped with single parenthesis (') because
* SQL databases expect that. Numbers are returned as-is.
*
* If the field is null, a string containing "NULL" is returned instead.
*
* #param f The field where the value is.
* #return Formatted value.
*/
String formatValue(Field f) {
String retval = null;
String type = f.getClass().getName();
if (type.equals("String")) {
try {
String value = (String)f.get(f);
if (value != null) {
retval = "'" + value + "'";
} else {
retval = "NULL";
}
} catch (Exception e) {
System.err.println("No such field: " + e.getMessage());
}
} else if (type.equals("Integer")) {
try {
Integer value = (Integer)f.get(f);
if (value != null) {
retval = String.valueOf(value);
} else {
retval = "NULL";
}
} catch (Exception e) {
System.err.println("No such field: " + e.getMessage());
}
} else {
try {
String value = (String) f.get(f);
if (value != null) {
retval = value;
} else {
retval = "NULL";
}
} catch (Exception e) {
System.err.println("No such field: " + e.getMessage());
}
}
return retval;
}
There are many different ways to achieve this (e.g proxies, ASM), but the simplest approach, one that you can start with when prototyping is:
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
public class MakeTodayClass {
Date today = new Date();
String todayMillis = Long.toString(today.getTime());
String todayClass = "z_" + todayMillis;
String todaySource = todayClass + ".java";
public static void main (String args[]){
MakeTodayClass mtc = new MakeTodayClass();
mtc.createIt();
if (mtc.compileIt()) {
System.out.println("Running " + mtc.todayClass + ":\n\n");
mtc.runIt();
}
else
System.out.println(mtc.todaySource + " is bad.");
}
public void createIt() {
try {
FileWriter aWriter = new FileWriter(todaySource, true);
aWriter.write("public class "+ todayClass + "{");
aWriter.write(" public void doit() {");
aWriter.write(" System.out.println(\""+todayMillis+"\");");
aWriter.write(" }}\n");
aWriter.flush();
aWriter.close();
}
catch(Exception e){
e.printStackTrace();
}
}
public boolean compileIt() {
String [] source = { new String(todaySource)};
ByteArrayOutputStream baos= new ByteArrayOutputStream();
new sun.tools.javac.Main(baos,source[0]).compile(source);
// if using JDK >= 1.3 then use
// public static int com.sun.tools.javac.Main.compile(source);
return (baos.toString().indexOf("error")==-1);
}
public void runIt() {
try {
Class params[] = {};
Object paramsObj[] = {};
Class thisClass = Class.forName(todayClass);
Object iClass = thisClass.newInstance();
Method thisMethod = thisClass.getDeclaredMethod("doit", params);
thisMethod.invoke(iClass, paramsObj);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
It is possible to generate classes (via cglib, asm, javassist, bcel), but you shouldn't do it that way. Why?
the code that's using the library should expect type Object and get all the fields using reflection - not a good idea
java is statically typed language, and you want to introduce dynamic typing - it's not the place.
If you simply want the data in an undefined format, then you can return it in an array, like Object[], or Map<String, Object> if you want them named, and get it from there - it will save you much trouble with unneeded class generation for the only purpose of containing some data that will be obtained by reflection.
What you can do instead is have predefined classes that will hold the data, and pass them as arguments to querying methods. For example:
public <T> T executeQuery(Class<T> expectedResultClass,
String someArg, Object.. otherArgs) {..}
Thus you can use reflection on the passed expectedResultClass to create a new object of that type and populate it with the result of the query.
That said, I think you could use something existing, like an ORM framework (Hibernate, EclipseLink), spring's JdbcTemplate, etc.
This is possible, but (I believe) you need something like ASM or BCEL.
Alternately, you could use something with more power (like Groovy).
It will take a couple of minutes to create a data model class for each table, which you can easily map to the database with an ORM like Hibernate or by writing your own JDBC DAOs. It is far easier than delving deeply into reflection.
You could create a utility that interrogates the database structure for a table, and creates the data model class and DAO for you. Alternatively you could create the model in Java and create a utility to create the database schema and DAO from that (using reflection and Java 5 Annotations to assist). Don't forget that javaFieldNames are different from database_column_names typically.
Recently I needed to create about 200 simple classes from medatata (objects filled with static data) and I did it through the open source burningwave library, with the following scenario:
The classes needed to have a certain prefix in the name, for example "Registro "*.java;
The classes needed to extend from a superclass Registro.java
The classes needed to contain JPA annotations like #Entity, #Column (in attributes), Lombok annotations and custom annotations.
Here is the link to the repository with the complete project: https://github.com/leandrosoares6/criacao-classes-entidade-efd
Here is the code snippet responsible for creating the classes:
public class RegistrosClassFactory {
private static final String PACOTE = "com.example.demo.model.registros";
private static final String SCHEMA = "MY_SCHEMA";
private static final String PREFIXO = "Registro";
static void criaRegistros() {
List<RegistroTest> registros = RegistroMetadataFactory.criaMetadados();
criaClasses(registros);
}
private static void criaClasses(List<RegistroTest> registros) {
for (RegistroTest registroTest : registros) {
UnitSourceGenerator gerador = UnitSourceGenerator.create(PACOTE);
ClassSourceGenerator registro = ClassSourceGenerator
.create(TypeDeclarationSourceGenerator.create(PREFIXO + registroTest.getNome()))
.addModifier(Modifier.PUBLIC)
.addAnnotation(AnnotationSourceGenerator.create(Getter.class))
.addAnnotation(AnnotationSourceGenerator.create(Setter.class))
.addAnnotation(AnnotationSourceGenerator.create(NoArgsConstructor.class))
.addAnnotation(AnnotationSourceGenerator.create(ToString.class))
.addAnnotation(AnnotationSourceGenerator.create(Entity.class))
.addAnnotation(AnnotationSourceGenerator.create(Table.class)
.addParameter("name",
VariableSourceGenerator.create(String.format("\"%s\"",
registroTest.getNomeTabelaBd())))
.addParameter("schema", VariableSourceGenerator
.create(String.format("\"%s\"", SCHEMA))));
criaColunas(registroTest.getCampos(), registro);
registro.addConstructor(FunctionSourceGenerator.create().addModifier(Modifier.PUBLIC)
.addParameter(VariableSourceGenerator.create(String.class, "linha"))
.addBodyCodeLine("super(linha);")).expands(Registro.class);
gerador.addClass(registro);
// System.out.println("\nRegistro gerado:\n" + gerador.make());
String caminhoPastaRegistros = System.getProperty("user.dir") + "/src/main/java/";
gerador.storeToClassPath(caminhoPastaRegistros);
}
}
private static void criaColunas(List<Campo> campos, ClassSourceGenerator registro) {
for (Campo campo : campos) {
VariableSourceGenerator field = VariableSourceGenerator
.create(TypeDeclarationSourceGenerator.create(String.class),
campo.getNomeAtributo())
.addModifier(Modifier.PRIVATE)
.addAnnotation(AnnotationSourceGenerator.create(Column.class)
.addParameter("name", VariableSourceGenerator
.create(String.format("\"%s\"", campo.getNome())))
)
.addAnnotation(AnnotationSourceGenerator.create(Indice.class).addParameter(
"valor",
VariableSourceGenerator.create(String.valueOf(campo.getSequencial()))));
if (campo.getNome().equals("ID")) {
field.addAnnotation(AnnotationSourceGenerator.create(Id.class));
}
if (campo.getEId()) {
field.addAnnotation(AnnotationSourceGenerator.create(CampoTipoId.class));
}
if (campo.getEData()) {
field.addAnnotation(AnnotationSourceGenerator.create(CampoTipoData.class));
}
if (campo.getEDataPart()) {
field.addAnnotation(AnnotationSourceGenerator.create(CampoTipoDataPart.class));
}
registro.addField(field);
}
}
}
I'm aware of the performance drawback of reflection but for my little project I needed this and I created a project lib which converts JSON to Java and then finally .class in JVM context.
Anyone need such thing can have a look into my open source solution, which requires JDK to compile the code.
https://medium.com/#davutgrbz/the-need-history-c91c9d38ec9?sk=f076487e78a1ff5a66ef8eb1aa88f930