jaxb and jsr303 - java

I am constructing object out of configuration using jaxb.
Until now I wrote custom function for validation but I would like to move into annotations.
e.g.:
#XmlElement
public void setNumber(Integer i){
if (i<10 || i>20) throw new IllegalArgumentException(...);
this.number=i;
}
The exceptions from this above approach were descriptive and gave me the position of the error in the xml.
I want to move into this:
#XmlElement
#Min(10)
#Max(20)
public void setNumber(Integer i){
this.number=i;
}
I can verify this by reading annotations in afterMarshal and running validation functions according to property annotations, but then I lose the actual place (in the xml) where the error occurred.
Do you have any though, should I use a different approach/framework for this problem?
EDIT: just to clarify, I must use annotation approach because I need the properties constraints metadata for the configuration editor I am writing

Here is a XJC plugin that I have used to solve this problem myself (in my case I needed annotations to do validation independant of XML schema, as I also have JMS endpoints):
What it does:
-It generates #valid annotation for objects that are not in the xs default schema (so annotations are cascaded)
-It generates #NotNull annotation for objects that has a MinOccur value >= 1 or for attributes with required use
-It generates #Size for lists that have minOccurs > 1
-It generates #Size if there is a maxLength or minLength restriction
-#DecimalMax for maxInclusive restriction
-#DecimalMin for minInclusive restriction
-#Digits if there is a totalDigits or fractionDigits restriction.
-#Pattern if there is a Pattern restriction
Please note that minExclusive and maxExclusive restrictions are excluded.
To use it, you have to package the class file along a META-INF/services/com.sun.tools.xjc.Plugin file with the content "com.sun.tools.xjc.addon.jaxb.JaxbValidationsPlugins" (that is, the fully qualified name of the class) and call XJC with the -XValidate switch.
It's not really difficult to implement, but I hope it will be useful for someone. The source code is attached as a TXT file. Enjoy!
package com.sun.tools.xjc.addon.jaxb;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.util.Collections;
import java.util.List;
import javax.validation.Valid;
import javax.validation.constraints.DecimalMax;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.Digits;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import org.xml.sax.ErrorHandler;
import com.sun.codemodel.JAnnotationUse;
import com.sun.codemodel.JFieldVar;
import com.sun.tools.xjc.Options;
import com.sun.tools.xjc.Plugin;
import com.sun.tools.xjc.model.CAttributePropertyInfo;
import com.sun.tools.xjc.model.CElementPropertyInfo;
import com.sun.tools.xjc.model.CPropertyInfo;
import com.sun.tools.xjc.outline.ClassOutline;
import com.sun.tools.xjc.outline.FieldOutline;
import com.sun.tools.xjc.outline.Outline;
import com.sun.xml.xsom.XSComponent;
import com.sun.xml.xsom.XSSimpleType;
import com.sun.xml.xsom.impl.AttributeUseImpl;
import com.sun.xml.xsom.impl.ElementDecl;
import com.sun.xml.xsom.impl.ParticleImpl;
public class JaxbValidationsPlugins extends Plugin {
public String getOptionName() {
return "Xvalidate";
}
public List<String> getCustomizationURIs() {
return Collections.singletonList(namespace);
}
private String namespace = "http://jaxb.dev.java.net/plugin/code-injector";
public boolean isCustomizationTagName(String nsUri, String localName) {
return nsUri.equals(namespace) && localName.equals("code");
}
public String getUsage() {
return " -Xvalidate : inject Bean validation annotations (JSR 303)";
}
public boolean run(Outline model, Options opt, ErrorHandler errorHandler) {
try {
for (ClassOutline co : model.getClasses()) {
for (CPropertyInfo property : co.target.getProperties()) {
if (property instanceof CElementPropertyInfo) {
recorrePropiedad((CElementPropertyInfo) property, co, model);
} else if (property instanceof CAttributePropertyInfo) {
recorrePropiedad((CAttributePropertyInfo) property, co, model);
}
}
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
static int i = 0;
/**
* XS:Element
*
* #param property
* #param clase
* #param model
*/
public void recorrePropiedad(CElementPropertyInfo property, ClassOutline clase, Outline model) {
FieldOutline field = model.getField(property);
XSComponent definicion = property.getSchemaComponent();
ParticleImpl particle = (ParticleImpl) definicion;
int maxOccurs = ((BigInteger) getField("maxOccurs", particle)).intValue();
int minOccurs = ((BigInteger) getField("minOccurs", particle)).intValue();
JFieldVar var = (JFieldVar) clase.implClass.fields().get(getField("privateName", property));
if (minOccurs < 0 || minOccurs >= 1) {
if (!hasAnnotation(var, NotNull.class)) {
System.out.println("#NotNull: " + property.getName() + " de la clase " + clase.implClass.name());
var.annotate(NotNull.class);
}
}
if(maxOccurs>1){
if (!hasAnnotation(var, Size.class)) {
System.out.println("#Size ("+minOccurs+","+maxOccurs+") " + property.getName() + " de la clase " + clase.implClass.name());
var.annotate(Size.class).param("min", minOccurs).param("max", maxOccurs);
}
}
ElementDecl declaracion = (ElementDecl) getField("term", particle);
if (declaracion.getType().getTargetNamespace().startsWith("http://hotelbeds.com")) {
if (!hasAnnotation(var, Valid.class)) {
System.out.println("#Valid: " + property.getName() + " de la clase " + clase.implClass.name());
var.annotate(Valid.class);
}
}
if (declaracion.getType() instanceof XSSimpleType) {
procesaType((XSSimpleType) declaracion.getType(), var, property.getName(), clase.implClass.name());
} else if (declaracion.getType().getBaseType() instanceof XSSimpleType) {
procesaType((XSSimpleType) declaracion.getType().getBaseType(), var, property.getName(), clase.implClass.name());
}
// if(declaracion.getType() instanceof
// if(declaracion.getType().ge)
// procesaType(declaracion.getType().getBaseType(),var);
}
/**
* XS:Attribute
*
* #param property
* #param clase
* #param model
*/
public void recorrePropiedad(CAttributePropertyInfo property, ClassOutline clase, Outline model) {
FieldOutline field = model.getField(property);
System.out.println("Tratando attributo " + property.getName() + " de la clase " + clase.implClass.name());
XSComponent definicion = property.getSchemaComponent();
AttributeUseImpl particle = (AttributeUseImpl) definicion;
JFieldVar var = (JFieldVar) clase.implClass.fields().get(getField("privateName", property));
if (particle.isRequired()) {
if (!hasAnnotation(var, NotNull.class)) {
System.out.println("#NotNull: " + property.getName() + " de la clase " + clase.implClass.name());
var.annotate(NotNull.class);
}
}
if (particle.getDecl().getType().getTargetNamespace().startsWith("http://hotelbeds.com")) {
if (!hasAnnotation(var, Valid.class)) {
System.out.println("#Valid: " + property.getName() + " de la clase " + clase.implClass.name());
var.annotate(Valid.class);
}
}
procesaType(particle.getDecl().getType(), var, property.getName(), clase.implClass.name());
}
public void procesaType(XSSimpleType tipo, JFieldVar field, String campo, String clase) {
if (tipo.getFacet("maxLength") != null || tipo.getFacet("minLength") != null) {
Integer maxLength = tipo.getFacet("maxLength") == null ? null : parseInt(tipo.getFacet("maxLength").getValue().value);
Integer minLength = tipo.getFacet("minLength") == null ? null : parseInt(tipo.getFacet("minLength").getValue().value);
if (!hasAnnotation(field, Size.class)) {
System.out.println("#Size(" + minLength + "," + maxLength + "): " + campo + " de la clase " + clase);
field.annotate(Size.class).param("min", minLength).param("max", maxLength);
}
}
/*
* <bindings multiple="true" node=
* "//xs:complexType/.//xs:element[contains(#type,'IntPercentRestriction')]"
* > <annox:annotate> <annox:annotate
* annox:class="javax.validation.constraints.Digits" integer="3"
* fraction="2" /> <annox:annotate
* annox:class="javax.validation.constraints.Min" value="-100" />
* value="100" /> </annox:annotate> </bindings>
*//*
* <xs:restriction base="xs:decimal"> <xs:fractionDigits value="2"/>
* <xs:maxInclusive value="100.00"/> <xs:minInclusive
* value="-100.00"/> <xs:totalDigits value="5"/> </xs:restriction>
*/
if (tipo.getFacet("maxInclusive") != null && tipo.getFacet("maxInclusive").getValue().value != null && !hasAnnotation(field,DecimalMax.class)){
System.out.println("#DecimalMax(" + tipo.getFacet("maxInclusive").getValue().value + "): " + campo + " de la clase " + clase);
field.annotate(DecimalMax.class).param("value", tipo.getFacet("maxInclusive").getValue().value);
}
if (tipo.getFacet("minInclusive") != null && tipo.getFacet("minInclusive").getValue().value != null && !hasAnnotation(field,DecimalMin.class)){
System.out.println("#DecimalMin(" + tipo.getFacet("minInclusive").getValue().value + "): " + campo + " de la clase " + clase);
field.annotate(DecimalMin.class).param("value", tipo.getFacet("minInclusive").getValue().value);
}
if (tipo.getFacet("totalDigits") != null) {
Integer totalDigits = tipo.getFacet("totalDigits") == null ? null : parseInt(tipo.getFacet("totalDigits").getValue().value);
int fractionDigits = tipo.getFacet("fractionDigits") == null ? 0 : parseInt(tipo.getFacet("fractionDigits").getValue().value);
if (!hasAnnotation(field, Digits.class)) {
System.out.println("#Digits(" + totalDigits + "," + fractionDigits + "): " + campo + " de la clase " + clase);
JAnnotationUse annox = field.annotate(Digits.class).param("integer", (totalDigits - fractionDigits));
if (tipo.getFacet("fractionDigits") != null) {
annox.param("fraction", fractionDigits);
}
}
}
/**
* <annox:annotate annox:class="javax.validation.constraints.Pattern"
message="Name can only contain capital letters, numbers and the simbols '-', '_', '/', ' '"
regexp="^[A-Z0-9_\s//-]*" />
*/
if(tipo.getFacet("pattern")!=null){
System.out.println("#Pattern(" +tipo.getFacet("pattern").getValue().value+ "): " + campo + " de la clase " + clase);
if (!hasAnnotation(field, Pattern.class)) {
field.annotate(Pattern.class).param("regexp", tipo.getFacet("pattern").getValue().value);
}
}
}
#SuppressWarnings({ "unchecked", "rawtypes" })
public boolean hasAnnotation(JFieldVar var, Class anotacion) {
List<JAnnotationUse> lista = (List<JAnnotationUse>) getField("annotations", var);
if (lista != null) {
for (JAnnotationUse uso : lista) {
if (((Class) getField("clazz._class", uso)).getCanonicalName().equals(anotacion.getCanonicalName())) {
return true;
}
}
}
return false;
}
private Integer parseInt(String valor) {
try {
Integer i = Integer.parseInt(valor);
if (i < 2147483647 && i > -2147483648) {
return i;
}
} catch (Exception e) {
try{
return (int)Math.round(Double.parseDouble(valor));
}catch(Exception ex){
;
}
}
return null;
}
/*
private Long parseLong(String valor) {
try {
Long i = Long.parseLong(valor);
if (i < 2147483647 && i > -2147483648) {
return i;
}
} catch (Exception e) {
return Math.round(Double.parseDouble(valor));
}
return null;
}
*/
private Object getField(String path, Object oo) {
try {
if (path.contains(".")) {
String field = path.substring(0, path.indexOf("."));
Field campo = oo.getClass().getDeclaredField(field);
campo.setAccessible(true);
Object result = campo.get(oo);
return getField(path.substring(path.indexOf(".") + 1), result);
} else {
Field campo = getSimpleField(path, oo.getClass());
campo.setAccessible(true);
return campo.get(oo);
}
} catch (Exception e) {
System.out.println("Field " + path + " not found on " + oo.getClass().getName());
}
return null;
}
private static Field getSimpleField(String fieldName, Class<?> clazz) {
Class<?> tmpClass = clazz;
try {
do {
for (Field field : tmpClass.getDeclaredFields()) {
String candidateName = field.getName();
if (!candidateName.equals(fieldName)) {
continue;
}
field.setAccessible(true);
return field;
}
tmpClass = tmpClass.getSuperclass();
} while (clazz != null);
} catch (Exception e) {
System.out.println("Field '" + fieldName + "' not found on class " + clazz);
}
return null;
}
}

You should look at https://github.com/krasa/krasa-jaxb-tools
which is improved and mavenized version of Vicente's code.

This depends on how are you reading the file and how do you plan to show errors. Using IAE is better if you also plan to construct the class programatically. Using JSR-303 is better when you also use it with JavaEE 6. Also, you must think if your user needs to know the error line number.
And remember: the first (pure-POJO) way ensures that no object will ever be inconsistent (marshalling or unmarshalling), while JSR-303 requires someone to call the validation functions (as well as requiring the framework classes in classpath).

Related

How to read value of java annotation with JDK8 and JDK11?

How to read value of java annotation with JDK8 and JDK11?
import io.cucumber.java.en.When;
public class Sof {
private static final Logger log = LoggerFactory.getLogger(Sof.class);
#When(value = "I update text {string} with {string}(\\?)")
public static void main(String[] args) {
Class c = Sof.class;
Method[] methods = c.getMethods();
Method method = null;
for (Method m : methods) {
if (m.getName().equals("main")) {
method = m;
}
}
Annotation stepAnnotation = method.getAnnotation(When.class);
Object as[] = { "a", "b" };
Matcher matcher = Pattern.compile("value=(.*)\\)").matcher(stepAnnotation.toString());
if (matcher.find()) {
log.info("---> " + stepAnnotation.annotationType().getSimpleName() + " " + String.format(matcher.group(1).replaceAll("\\{\\S+\\}", "{%s}").replace("(\\?)", ""), as));
} else {
System.err.println("error");
}
}
}
/!\ in reality, I do not know the type of annotation #When. this can be any of the interfaces in the io.cucumber.java package
result JDK8:
---> When I update text {a} with {b}
result JDK11 (extra quote): (stepAnnotation.toString() is different!)
---> When "I update text {a} with {b}"
EDIT openjdk11 and oraclejdk11 do not respect javadoc:
/**
* Returns a string representation of this annotation. The details
* of the representation are implementation-dependent, but the following
* may be regarded as typical:
* <pre>
* #com.acme.util.Name(first=Alfred, middle=E., last=Neuman)
* </pre>
*
* #return a string representation of this annotation
*/
String toString();
You should not depend on the toString() implementation which is normally for debugging/logging only.
See Is it possible to read the value of a annotation in java? for more details on how to read the value of an annotation.
UPDATE:
To do everything via reflection, you can so something like this:
import org.springframework.transaction.annotation.Transactional;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
public class AnnotationTest {
public static void main(String[] args) throws IllegalAccessException, InvocationTargetException {
Method[] methods = AnnotationTest.class.getMethods();
System.out.println("methods = " + Arrays.toString(methods));
for (Method method : methods) {
System.out.println("method = " + method);
Annotation[] annotations = method.getAnnotations();
System.out.println("annotations = " + Arrays.toString(annotations));
for (Annotation annotation : annotations) {
System.out.println("annotation = " + annotation);
Class<? extends Annotation> annotationClass = annotation.annotationType();
System.out.println("annotationClass = " + annotationClass);
Method[] annotationMethods = annotationClass.getMethods();
System.out.println("annotation methods = " + Arrays.toString(annotationMethods));
for (Method annotationMethod : annotationMethods) {
if (Modifier.isPublic(annotationMethod.getModifiers())) {
String name = annotationMethod.getName();
Object o = annotationMethod.invoke(annotation);
System.out.println(name + ": " + o);
}
}
}
}
}
#Transactional("bla")
public void test() {
}
}
(I used one of Spring's annotations here since that is what I happen to have on my classpath)
UPDATE (with end of solution):
#When(value = "I update text {string} with {string}(\\?)")
public static void main(String[] args) {
Object as[] = { "a", "b" };
Class c = Sof.class;
Method[] methods = c.getMethods();
Method method = null;
for (Method m : methods) {
if (m.getName().equals("main")) {
method = m;
}
}
Annotation stepAnnotation = method.getAnnotation(When.class);
Class<? extends Annotation> annotationClass = stepAnnotation.annotationType();
try {
Method valueMethods = annotationClass.getDeclaredMethod("value");
if (Modifier.isPublic(valueMethods.getModifiers())) {
log.info("---> {} " + String.format(valueMethods.invoke(stepAnnotation).toString().replaceAll("\\{\\S+\\}", "{%s}").replace("(\\?)", ""), as),
stepAnnotation.annotationType().getSimpleName());
}
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) {
e1.printStackTrace();
}
}

Polymorphic deserialization of JSON with jackson with type info from parent node

I have this JSON documents
1:
{
"type": "first_type",
"configs": [
{
"itemLevel": 1,
"power": {
"firstTypeParam": "xxxx"
}
},
{
"itemLevel": 2,
"power": {
"firstTypeParam": "yyy"
}
}
]
}
2:
{
"type": "second_type",
"configs": [
{
"itemLevel": 11,
"power": {
"anotherParam": true
}
},
{
"itemLevel": 12,
"power": {
"anotherParam": false
}
]
}
A couple of java classes
public class Dto {
String type;
Collection<Config>;
}
public class Config {
int itemLevel;
Collection<Power> powers;
}
public interface Power {}
public class FirstPower implements Power {
String firstTypeParam;
}
public class SecondPower implements Power {
boolean anotherParam;
}
I tried to implement custom jackson deserializer #JsonDeserialize(using = MyStdDeserializer.class" on top of Power interface but couldn't find out how to access to neighbor node of the parent with type flag.
Do you know how to fix class hierarchy and/or use jackson features/annotations to deserialize JSON with "first_type" type onto FirstPower class and "second_type" onto SecondPower?
I'm using jackson 2.9.7
It is possible to change class hierarchy and JSON format little bit and also I have ability to use annotation-based deserialization.
Since the type information is stored in Dto class, the custom JsonDeserializer should be implemented for 'Dto' class instead of 'Power' interface in order to access the type information. The crucial part of the implementation of the custom JsonDeserializer in below code is the line
config.powers.add(parser.readValueAs(getPowerClass(dto.type)));
where getPowerClass method determine the class(FirstPower or SecondPower) required by using the type of dto. Once the class is known, we can deserialize the power object simply by calling readValueAs method. Following classes(should be put in same package) demonstrate how to implement the custom JsonDeserializer.
Main class
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class PolymorphicDeserialize {
public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
ObjectMapper mapper = new ObjectMapper();
Dto type1 = mapper.readValue(getType1Json(), Dto.class);
Dto type2 = mapper.readValue(getType2Json(), Dto.class);
printDto(type1);
printDto(type2);
}
private static void printDto(Dto dto) {
System.out.println("type :" + dto.type);
for (Config config : dto.configs) {
System.out.println("itemLevel:" + config.itemLevel);
System.out.println("powers:" + config.powers);
}
}
private static String getType1Json() {
return " { "
+ " \"type\": \"first_type\", "
+ " \"configs\": [ "
+ " { "
+ " \"itemLevel\": 1, "
+ " \"power\": { "
+ " \"firstTypeParam\": \"xxxx\" "
+ " } "
+ " }, "
+ " { "
+ " \"itemLevel\": 2, "
+ " \"power\": { "
+ " \"firstTypeParam\": \"yyy\" "
+ " } "
+ " } "
+ " ] "
+ " } ";
}
private static String getType2Json() {
return " { "
+ " \"type\": \"second_type\", "
+ " \"configs\": [ "
+ " { "
+ " \"itemLevel\": 11, "
+ " \"power\": { "
+ " \"anotherParam\": true "
+ " } "
+ " }, "
+ " { "
+ " \"itemLevel\": 12, "
+ " \"power\": { "
+ " \"anotherParam\": false "
+ " } "
+ " } "
+ " ] "
+ " } ";
}
}
Dto class
import java.util.Collection;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
#JsonDeserialize(using = DtoDeserializer.class)
public class Dto {
String type;
Collection<Config> configs;
}
DtoDeserializer class
import java.io.IOException;
import java.util.ArrayList;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
public class DtoDeserializer extends JsonDeserializer<Dto> {
#Override
public Dto deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
Dto dto = new Dto();
dto.configs = new ArrayList<Config>();
while (parser.nextToken() == JsonToken.FIELD_NAME) {
deserializeType(parser, dto);
deserializeConfigs(parser, dto);
}
return dto;
}
private void deserializeType(JsonParser parser, Dto dto) throws IOException, JsonProcessingException {
if (!"type".equals(parser.getCurrentName())) {
return;
}
parser.nextToken();
dto.type = parser.getValueAsString();
}
private void deserializeConfigs(JsonParser parser, Dto dto) throws IOException, JsonProcessingException {
if (!"configs".equals(parser.getCurrentName())) {
return;
}
if (parser.nextToken() != JsonToken.START_ARRAY) {
return;
}
while (parser.nextValue() != null) {
if (parser.getCurrentToken() != JsonToken.START_OBJECT) {
continue;
}
Config config = new Config();
config.powers = new ArrayList<Power>();
while (parser.nextToken() != JsonToken.END_OBJECT) {
if ("itemLevel".equals(parser.getCurrentName())) {
parser.nextToken();
config.itemLevel = parser.getValueAsInt();
} else if ("power".equals(parser.getCurrentName())) {
parser.nextToken();
config.powers.add(parser.readValueAs(getPowerClass(dto.type)));
}
}
dto.configs.add(config);
}
}
private Class<? extends Power> getPowerClass(String type) {
if ("first_type".equals(type)) {
return FirstPower.class;
} else if ("second_type".equals(type)) {
return SecondPower.class;
}
throw new IllegalArgumentException("Not known type" + type);
}
}
Power interface
public interface Power {}
FirstPower class
public class FirstPower implements Power {
String firstTypeParam;
String getFirstTypeParam() {
return firstTypeParam;
}
void setFirstTypeParam(String firstTypeParam) {
this.firstTypeParam = firstTypeParam;
}
#Override
public String toString() {
return "firstTypeParam:" + firstTypeParam;
}
}
SecondPower class
public class SecondPower implements Power {
boolean anotherParam;
boolean isAnotherParam() {
return anotherParam;
}
void setAnotherParam(boolean anotherParam) {
this.anotherParam = anotherParam;
}
#Override
public String toString() {
return "anotherParam:" + String.valueOf(anotherParam);
}
}

ResultSet only returns one row when more exist in the database

I created a java class called Executar_Query_Bd_Multiplos_Resultados in this class as the parameter for the Conectar method 2 values (int Integer1, int Integer2) of integer type.
These values are received by the query:
"SELECT DS_ESTRATEGY, STRID_ID" +
"FROM TB_BKOFFICE_ESTRATEGY" +
"WHERE IN_STRATEGY_ID IN (" + Istrategy1 + "," + Istrategy2 + ")";
The result of the above query is stored in the variable ls_command.
In the Executar_Query_Bd_Multiplos_Resultados_Test class I make the method call (Connect) and step 2 parameters (179, 319) and command to print on the screen the variable of type String codEstrategies.
But Eclipse only displays 1 result on the console. The query should bring 2 results and not 1. Here is the code for the Java classes and the result of the query executed in Oracle SQL Developer.
public class Executar_Query_Bd_Multiplos_Resultados_Test {
#Before
public void setUp() throws Exception {
Executar_Query_Bd_Multiplos_Resultados qr_2 = new Executar_Query_Bd_Multiplos_Resultados();
String codEstrategias = qr_2.Conectar(179, 319);
System.out.println("Estratégias: " + codEstrategias);
}
#After
public void tearDown() throws Exception {
}
#Test
public void test() {
}
}
public class Executar_Query_Bd_Multiplos_Resultados {
//Variáveis de BD
Connection conOracle = null;
Statement stmtOracle = null;
ResultSet rsetOracle = null;
public String Conectar(int Id_Estrategia1, int Id_Estrategia2) {
String retorno = "#;-1;#";
Boolean lb_continuar = true;
//StringBuilder ls_comando = new StringBuilder();
String ls_comando = new String();
try {
System.out.println("Conectando ao banco de dados Oracle...");
String url = "";
try {
//conectando aos bancos de dados
Class.forName("oracle.jdbc.driver.OracleDriver");
url = "jdbc:oracle:thin:#10.5.12.116:1521:desenv01";
DriverManager.setLoginTimeout(10);
conOracle = (Connection) DriverManager.getConnection(url, "bkofficeadm", "bkofficeadmdesenv01");
} catch (SQLException e) {
System.out.println("falha SQL >> " + e.getMessage());
} catch (Exception e) {
//System.out.println("falha geral >> " + e.getMessage());
e.printStackTrace();
lb_continuar = false;
}
//String teste = "'BKO - Rep Conectividade'";
if (lb_continuar) {
System.err.println("Preparando comando...");
System.out.println("");
ls_comando = "SELECT DS_ESTRATEGIA, ID_ESTRATEGIA"+
" FROM TB_BKOFFICE_ESTRATEGIA"+
" WHERE ID_ESTRATEGIA IN (" + Id_Estrategia1 + ", " + Id_Estrategia2 + ")";
System.out.println(ls_comando);
stmtOracle = conOracle.createStatement();
stmtOracle.setQueryTimeout(10);
rsetOracle = stmtOracle.executeQuery(ls_comando.replaceAll("\n", " ").trim());
if(rsetOracle.next()) {
retorno = rsetOracle.getString(1);
}
rsetOracle.close();
stmtOracle.close();
/*
Para comandos de Insert, Delete, ou Update
--------------------------------------------------------
stmtOracle = conOracle.createStatement();
stmtOracle.setQueryTimeout(10);
stmtOracle.execute(variavel_comando.toString());
conOracle.commit();
stmtOracle.close();
*/
}
} catch (Exception ex) {
System.out.println("Erro - " + ex.getMessage());
} finally {
try {
if (rsetOracle != null) {
rsetOracle.close();
}
} catch (Exception e) {
System.out.println("Erro ao fechar rset - " + e.getMessage());
}
try {
if (stmtOracle != null) {
stmtOracle.close();
}
} catch (Exception e) {
System.out.println("Erro ao fechar stmt - " + e.getMessage());
}
try {
if (conOracle != null && !conOracle.isClosed()) {
conOracle.close();
}
if (conOracle != null && !conOracle.isClosed()) {
conOracle.close();
}
} catch (Exception e) {
System.out.println("Erro ao fechar con - " + e.getMessage());
}
}
return retorno;
}
}
Output from SQL Devleoper query:
Output from Eclipse console:
You're doing this
if(rsetOracle.next()) {
retorno = rsetOracle.getString(1);
}
This runs once
Consider while instead:
List<String> retornos = new ArrayList<>();
while(rsetOracle.next()) {
retornos.add(rsetOracle.getString(1));
}
This will run until you're out of rows.
If something like this happens in the future, you'll want to modify your query to select count(*) ... and verify you get the same result in both the database workbench and your javacode. Then you'll at least know you've got the right query, and it's your presentation that's failing.
Note:
I understand this question is indeed a duplicate of other questions. However, those are difficult to search. I would propose this be a canonical answer.

JPA trying to remove entity

I'm using a method to save a object in database, see:
#Transactional(propagation = Propagation.REQUIRED)
public void movimentarCaixa(String descricao,
AbstractBean donoCaixa, FormaPagamento formaPagamento, HistoricoPagamento historicoPagamento, double valor) {
try {
HistoricoCaixa historicoCaixa;
if (donoCaixa instanceof Dentista) {
logger.info("Iniciando movimentacao caixa para Dentista. Valor: "+valor);
historicoCaixa = new HistoricoCaixaDentista();
((Dentista) donoCaixa).setCaixaSaldoAtual(((Dentista) donoCaixa).getCaixaSaldoAtual()
+ valor);
((HistoricoCaixaDentista) historicoCaixa).setDentista((Dentista) donoCaixa);
} else if (donoCaixa instanceof Paciente) {
logger.info("Iniciando movimentacao caixa para Paciente. Valor: "+valor);
historicoCaixa = new HistoricoCaixaPaciente();
((Paciente) donoCaixa).setCaixaSaldoAtual(((Paciente) donoCaixa).getCaixaSaldoAtual()
+ valor);
((HistoricoCaixaPaciente) historicoCaixa).setPaciente((Paciente) donoCaixa);
} else if (donoCaixa instanceof Clinica) {
logger.info("Iniciando movimentacao caixa para Clinica. Valor: "+valor);
historicoCaixa = new HistoricoCaixaClinica();
Clinica clinica = (Clinica) donoCaixa;
if (formaPagamento == null || formaPagamento.getCodigo().equals("DINHEIRO")){
clinica.setSaldoDinheiro(clinica.getSaldoDinheiro() + valor);
} else if (formaPagamento.getCodigo().equals("CHEQUE")) {
clinica.setSaldoCheque(clinica.getSaldoCheque() + valor);
} else if (formaPagamento.getCodigo().equals("DEBITO")) {
clinica.setSaldoDebito(clinica.getSaldoDebito() + valor);
} else if (formaPagamento.getCodigo().equals("CREDITO")) {
clinica.setSaldoCredito(clinica.getSaldoCredito() + valor);
}
((HistoricoCaixaClinica) historicoCaixa).setClinica((Clinica) donoCaixa);
} else {
throw new MyException(
"O parametro 'donoCaixa' deve ser do tipo Dentista, Paciente ou Clinica");
}
historicoCaixa.setDataHora(historicoPagamento.getDataHora());
historicoCaixa.setDescricao(descricao);
historicoCaixa.setFormaPagamento(formaPagamento);
historicoCaixa.setHistoricoPagamento(historicoPagamento);
historicoCaixa.setUsuario((Usuario) SessionContext.getInstance().getUsuarioLogado());
historicoCaixa.setValor(valor);
this.getDao().save(historicoCaixa);
} catch (Exception e) {
e.printStackTrace();
}
}
I call this method twice, in the first time the variable "historicoCaixa" receives "new HistoricoCaixaPaciente()" instance and in second time this same variable receives "new HistoricoCaixaClinica()". The problem is that in second call i got error:
Caused by: java.lang.IllegalArgumentException: Removing a detached instance br.com.odontonew.financeiro.bean.HistoricoCaixaClinica#94
I imagine that JPA is trying to remove HistoricoCaixaClinica#94 but i don't want this, how can i avoid it ?

parse recursively unknown json input structure in java

I'm trying to parse recursively unknown json input structure in java like the format below and trying to rewrite the same structure in another json.
Meanwhile I need to validate each & every json key/values while parsing.
{"Verbs":[{
"aaaa":"30d", "type":"ed", "rel":1.0, "id":"80", "spoken":"en", "ct":"on", "sps":null
},{
"aaaa":"31", "type":"cc", "rel":3.0, "id":"10", "spoken":"en", "ct":"off", "sps":null
},{
"aaaa":"81", "type":"nn", "rel":3.0, "id":"60", "spoken":"en", "ct":"on", "sps":null
}]}
Please advice which json parser I can use for reading and writing unknown json content.
This way you can recursively parse JSON object:
import com.eclipsesource.json.JsonArray;
import com.eclipsesource.json.JsonObject;
import com.eclipsesource.json.JsonValue;
public class JsonQuestion {
public static void main(String[] args) {
String input = "{\"Verbs\":[{\n" +
" \"aaaa\":\"30d\", \"type\":\"ed\", \"rel\":1.0, \"id\":\"80\", \"spoken\":\"en\", \"ct\":\"on\", \"sps\":null\n" +
"},{\n" +
" \"aaaa\":\"31\", \"type\":\"cc\", \"rel\":3.0, \"id\":\"10\", \"spoken\":\"en\", \"ct\":\"off\", \"sps\":null\n" +
"},{\n" +
" \"aaaa\":\"81\", \"type\":\"nn\", \"rel\":3.0, \"id\":\"60\", \"spoken\":\"en\", \"ct\":\"on\", \"sps\":null\n" +
"}]}";
JsonObject jsonObject = JsonObject.readFrom(input);
handleObject(jsonObject);
}
private static void handleValue(JsonObject.Member member, JsonValue value) {
if (value.isArray()) {
if (member != null) {
System.out.print("name = " + member.getName());
}
System.out.println("array value ");
recurseArray(value.asArray());
} else if (value.isBoolean()) {
if (member != null) {
System.out.print("name = " + member.getName());
}
System.out.println(", boolean value = " + value.asBoolean());
} else if (value.isNull()) {
if (member != null) {
System.out.print("name = " + member.getName());
}
System.out.println(", null value");
} else if (value.isNumber()) {
if (member != null) {
System.out.print("name = " + member.getName());
}
System.out.println(", number value = " + value.asDouble());
} else if (value.isObject()) {
if (member != null) {
System.out.print("name = " + member.getName());
}
System.out.println(", object value ");
handleObject(value.asObject());
} else if (value.isString()) {
if (member != null) {
System.out.print("name = " + member.getName());
}
System.out.println(", string value = " + value.asString());
}
}
private static void handleObject(JsonObject object) {
for (JsonObject.Member next : object) {
JsonValue value = next.getValue();
handleValue(next, value);
}
}
private static void recurseArray(JsonArray array) {
for (JsonValue value : array) {
handleValue(null, value);
}
}
}
Using gson library
https://sites.google.com/site/gson/gson-user-guide
public void parseJson() {
String jsonStr = "";//input json String.
JsonParser parser = new JsonParser();
JsonElement jsonElement = parser.parse(jsonStr);
processJsonElement(jsonElement);
}
private void processJsonElement(JsonElement e) {
if (e.isJsonArray()) {
processJsonArray(e.getAsJsonArray());
} else if (e.isJsonNull()) {
processJsonNull(e.getAsJsonNull());
} else if (e.isJsonObject()) {
processJsonObject(e.getAsJsonObject());
} else if (e.isJsonPrimitive()) {
processJsonPrimitive(e.getAsJsonPrimitive());
}
}
private void processJsonArray(JsonArray a) {
for (JsonElement e : a) {
processJsonElement(e);
}
}
private void processJsonNull(JsonNull n) {
System.out.println("null || : " + n);
}
private void processJsonObject(JsonObject o) {
Set<Map.Entry<String, JsonElement>> members= o.entrySet();
for (Map.Entry<String, JsonElement> e : members) {
System.out.println("Processing object member: " + e.getKey());
processJsonElement(e.getValue());
}
}
private void processJsonPrimitive(JsonPrimitive p) {
System.out.println("Primitive || :" + p);
}
Or Jackson
public void processJson() {
ObjectMapper objectMapper = new ObjectMapper();
try {
JsonNode node = objectMapper.readTree(jsonStr);
System.out.println(node);
processNode(node);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void processNode(JsonNode n) {
if (n.isContainerNode()) {
processJsonContainer(n.iterator());
} else if (n.isNull()) {
System.out.println("Null || :" + n);
} else if (n.isNumber()) {
System.out.println("Number || :" + n.asDouble());
} else if (n.isBoolean()) {
System.out.println("Boolean || :" + n.asBoolean());
} else if (n.isTextual()) {
System.out.println("Text || :" + n.asText());
}
}
private void processJsonContainer(Iterator<JsonNode> iterator) {
while (iterator.hasNext()) {
processNode(iterator.next());
}
}

Categories