Play Excel module weird behaviour - java

I am using Play with Excel module 1.2.3. In a controller, I get a list of Students by calling a method defined in the model - Student:
List<Student> students= Student.findStudents();
findStudents() is defined as:
public static List<Student> findStudents() {
List<Student> list = Student.find("colA != colB").fetch();
return list;
}
then I render the excel file by:
renderExcel("student_report");
Inside the excel template, I have used JXLS. For example:
<jx:forEach items="${students}" var="stu">
${stu.address.name} ${stu.name}
</jx:forEach>
Now, the weird thing happens. stu.name always get displayed fine. However, stu.address.name only get displayed when I have done something like System.out.println(student.address.name) in the code. Otherwise, the cell in the Excel report is blank.
Can anyone explain this?
N.B. Student lazily ref to address

Jxls uses Apache Jexl to process property expressions like stu.address.name. Jexl uses reflection to calculate the object property values.
But reflection and lazy loading do not go along because you work not with a real object but with a proxy object.
When you do System.out.println(student.address.name) the real object is instantiated and the reflection works fine.
Possible solution to the issue is described in this answer Converting Hibernate proxy to real object. Or you just should do eager fetching whenever you need to pass the object to Jxls.

Related

How to populate default values of fields while creating issues in JIRA using jira-plugin?

I am working on jira-plugin to create issues in JIRA. I am using the method - create(user,createValidationResult) to create issue.
I need to give values of mandatory fields while creating.
I want to give the default values of fields while creating. (The default values are the ones which are configured during the creation of these in JIRA)
I have found the below methods
method populateDefaults
method getDefaultValue
But both the methods require Issue- parameter which is not yet created as I need to create the issue after setting default values
Please let me know how to set the values for these fields. These fields are added using method addCustomFieldValue in the class IssueInputParameters
I found the solution myself : (This works perfectly)
Use the below method :
IssueInputParameters issueInputParameters =
issueService.newIssueInputParameters();
issueInputParameters.setApplyDefaultValuesWhenParameterNotProvided(true);
IssueService.CreateValidationResult createValidationResult =
issueService.validateCreate(user, issueInputParameters);
issueService.create(user,createValidationResult);
Note : In the above code 'issueService' is an object of IssueService.

Problems with binding forms in Java controller

I am working on playframework and I have problem with scala forms when i apply the .get() methode to the form to create object i got all the object attributes are null.
here is my code:
import play.data.*;
import static play.data.Form.*;
public static Result save() {
Form<myobj> boundForm = cardForm.bindFromRequest();
if(boundForm.hasErrors()) {
flash("error", "Please correct the form below.");
return badRequest(page1.render(boundForm));
}
myobj temp= boundForm.get();
temp.save();
.
.
.
}
the problem is all the attributes in "temp" are null although when i add breakpoint in the intellij-idea and see the values inside the form i see that it has data
I had the same issue, the data binding stopped working at some point and all attributes was null.
The form.getData() gave back a map where all data was present, but the form's object was empty (all attribute null).
I suspected there is an error with the reflection, so deleted the target directory and compiled the classes again with the play framework. And now it works again.
I think it is a compatibility issue with the idea compiler versus play compiler, but I hadn't investigated the problem further.

Dynamically creating a JSF form with java reflection

I'm trying to create a simple crud form to insert data into a database with hibernate, without knowing what the object type is. The ultimate goal is to only have one insert form for every table in the database. So far i get the methods that the current object has, check to see if it has any set methods and create a text input for every field that has a set.
UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
HtmlPanelGrid hpg = (HtmlPanelGrid) viewRoot.findComponent("panel");
for (Method method : declaredFields) {
String name = method.getName();
if (name.contains("set")) {
HtmlOutputText hot = new HtmlOutputText();
HtmlInputText hit = new HtmlInputText();
hot.setValue(name.substring(3));
try {
hit.setValue(newObject.getClass().getMethod(name, String.class));
} catch (Exception ex) {
Logger.getLogger(ReflectController.class.getName()).log(Level.SEVERE, null, ex);
}
hpg.getChildren().add(hot);
hpg.getChildren().add(hit);
}
}
Here newObject is the object that is going to be inserted into the database later with hibernate. My problem is this:
How do assign a certain field from that object to the text input that is being created at the moment. So far if I put the method in the value like I'm doing above, it will just print out the method in the value attribute for that input. what i want is that when this form is submited, for to assign the value in that text box to the property with that name.
I can give you a partial answer - You need to create a ValueExpression dynamically
Application app = FacesContext.getCurrentInstance().getApplication();
hit.setValueExpression("value", app.getExpressionFactory().createValueExpression(FacesContext.getCurrentInstance().getELContext(), "#{bean.item}", Item.class));
The hard part will be creating the valueExpression that will actually map to a field within your object's value. That requires a great deal more thought but you will for sure need the dynamic valueExpression. As written, this will result in the execution of your bean's setItem();method with a parameter of type Item. You will require something a little more complex.
In JSF, binding input components to properties is accomplished with EL-expressions. You can create one programmatically as Steve shows, but that syntax is really ugly. On a related note, programmatic manipulation of the component tree is a rather unorthodox way of using JSF. The orthodox way to tackle your requirement would be something like:
<ui:repeat var="prop" value="#{genericEditorBean.propertyNames}">
<h:outputLabel value="#{prop}" for="input"/>
<h:inputText id="input" value="#{genericEditorBean.object[prop]}"/>
</ui:repeat>
where
public List<String> getPropertyNames() {
List<String> propertyNames = new ArrayList<>();
BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());
for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
propertyNames.add(pd.getName());
}
return propertyNames;
}
(There really is no reason to reimplement scanning for Java Bean properties when the Java API offers a class for that very purpose. Unlike your home-grown version, this will also handle properties inherited from a super class ...)
I once used an open-source library named MetaWidget to do this.
It was a few years ago, but it worked well and was easy to set up.
It looks like the project is still active:
http://metawidget.sourceforge.net/index.php

JAXBElement<Byte> declaration

I've generated classes from my XML .xsd and am trying to set a field EndpointID within in the class MeterSessionInputRF. The problem I'm having is that the setEndpointID method only accepts JAXBElement<Byte> as it's parameter.
I'm currently query a database to get the input for the setEndpointID method. This input can be a string, char, whatever I want it to be.
How do I create a JAXBElement<Byte>? I've tried using the ObjectFactory class but when I try and use it, I don't have the option of creating such an object.
Here's the code I already have to give some perspective.
if(moduleResults.next()){
MeterSessionInputRF msiRF = new MeterSessionInputRF();
msiRF.setRFFrequency(moduleResults.getFloat("id_amr_module"));
JAXBElement<Byte> endpointType;
byte epT = moduleResults.getByte("cd_module_typ");
endpointType.setValue(epT);
msiRF.setEndpointType(endpointType);
}
I keep getting the error that endpointType may have not been initialized. Is there a correct way to create the JAXBElement<Byte>?
The ObjectFactory class generated by XJC should have a method to do that for you. I know you said it wasn't there, but check again, there should be some method that returns an object of that type.

how to automatically copy values from java bean to protobuf message object using java reflection?

Typically I could copy values between two java beans, which have identical property names, using BeanUtils with java reflection e.g. PropertyUtils.setProperty(....)
In protobuf Message, we use the message builder class to set the value. This works but I would rather use reflection to automatically copy properties from the bean to the message as both have identical property names and type.
When I invoke the PropertyUtils.setProperty on the builder object ( got from message.newBuilder()), I get this message.
java.lang.NoSuchMethodException: Property 'testProp' has no setter method in class 'class teststuff.TestBeanProtos$TestBeanMessage$Builder'
How do I automatically copy values from java bean to protobuf message object (and vice-versa) using java reflection?
I hate to answer my question but I cant believe that I am the only one who ran into this problem. Documenting solution here in case other people are also getting started with protobuf and java. Using reflection saves wrting dozens of getter and setters.
Ok , I managed to get it to work using some of example test code shipping with protobuf. This is a very simple use case; typically a message would be a lot more complex. This code does not handle nested messages or repeated messages.
public static void setMessageBuilder(com.google.protobuf.GeneratedMessage.Builder message,Descriptors.Descriptor descriptor,Object srcObject) throws Exception {
String cname = srcObject.getClass().getName();
/*BeanMapper.getSimpleProperties -- this is a warpper method that gets the list of property names*/
List<String> simpleProps = BeanMapper.getSimpleProperties(srcObject.getClass());
Map map = new HashMap();
for (String pName : simpleProps) {
System.out.println(" processing property "+ pName);
Object value= PropertyUtils.getProperty(srcObject, pName);
if(value==null) continue;
Descriptors.FieldDescriptor fd=descriptor.findFieldByName(pName) ;
System.out.println(" property "+ pName+" , found fd :"+ (fd==null ? "nul":"ok"));
message.setField(fd, value);
System.out.println(" property "+ pName+" set ok,");
}
return ;
}
I may be off, but would protostuff help? It has nice extended support for working with other data formats, types. And even if it didn't have direct conversion support, if you go to/from JSON there are many choices for good data binding.
You can go throw all properties getClass().getFields() and make copy using reflection. It will be smt like:
for(Field f : to.getClass().getFields()){
f.set(to, from.getClass().getField(f.getName()).get(from));
}
+ probably you might be use field.setAccessible(true) invocation.
I don't know the size of your project but you may want to try Dozer, a mapper that recursively copies data from one object to another of the same type or between different complex types. Supports implicit and explicit mapping as well. I used it in a big project and worked very well. It could be as simple as
Mapper mapper = new DozerBeanMapper();
DestinationObject destObject = mapper.map(sourceObject, DestinationObject.class);
I've got the same issue, the solution is a little bit tricky.
Please use
MethodUtils.invokeMethod
instead.
where the method name is "setXXX".

Categories