Hi i am working on a spring mvc application well i need to Serialize an object in order to pass it with an ajax Post.
my bean class :
#JsonSerialize(using = AgentSer.class)
public class AgentCust implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Long personneID;
private String nom;
private String prenom;
private String matriculation;
private String marche;
private String compte;
private String phone, mail, chat;
public String getMarche() {
return marche;
}
public void setMarche(String marche) {
this.marche = marche;
}
public String getCompte() {
return compte;
}
public void setCompte(String compte) {
this.compte = compte;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getMail() {
return mail;
}
public void setMail(String mail) {
this.mail = mail;
}
public String getChat() {
return chat;
}
public void setChat(String chat) {
this.chat = chat;
}
public Long getPersonneID() {
return personneID;
}
public void setPersonneID(Long personneID) {
this.personneID = personneID;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public String getPrenom() {
return prenom;
}
public void setPrenom(String prenom) {
this.prenom = prenom;
}
public String getMatriculation() {
return matriculation;
}
public void setMatriculation(String matriculation) {
this.matriculation = matriculation;
}
}
and the class that will serialize my bean :
public class AgentSer extends JsonSerializer<AgentCust> {
#Override
public void serialize(AgentCust value, JsonGenerator jgen, SerializerProvider arg2) throws IOException, JsonProcessingException {
// TODO Auto-generated method stub
jgen.writeStartObject();
jgen.writeNumber(value.getPersonneID());
jgen.writeString(value.getMatriculation());
jgen.writeString(value.getNom());
jgen.writeString(value.getPrenom());
jgen.writeString(value.getCompte());
jgen.writeString(value.getMarche());
jgen.writeString(value.getChat());
jgen.writeString(value.getMail());
jgen.writeString(value.getPhone());
jgen.writeEndObject();
}
}
in my controller i use my class like that:
AgentCust ags ;
// i set values here .
ObjectMapper mapper = new ObjectMapper();
String json = "";
try {
json = mapper.writeValueAsString(ags);
} catch (Exception e) {
System.out.println(e);
}
but at the end i get that :
org.codehaus.jackson.JsonGenerationException: Can not write number, expecting field name
any help please.
Why are you using a custom serializer(which is wrong as it doesn't include the field names). You are really complicating your life.
You can set the serialization options like this (you can also set them in a static block):
final ObjectMapper mapper = new ObjectMapper();
/*
you can set them globally in a static block and reuse the mapper...
performance gain
*/
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
mapper.configure(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false);
mapper.setSerializationInclusion(Include.NON_NULL);
The rest of the code is the same(just add a constructor in your AgentCust.class to avoid some mapping errors):
AgentCust ags = new AgentCust();
ags.setChat("chat1");
ags.setCompte("compte1");
ags.setMail("mail1");
ags.setMarche("marche1");
ags.setMatriculation("matriculation1");
ags.setNom("nom1");
ags.setPersonneID(123456L);
ags.setPhone("phone1");
ags.setPrenom("prenom1");
String json = "";
try {
json = mapper.writeValueAsString(ags);
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(json);
Another strange thing is that you're serializing the pojo as String. Why not JsonNode or ObjectNode?
public static ObjectNode convObjToONode(Object o) {
StringWriter stringify = new StringWriter();
ObjectNode objToONode = null;
try {
mapper.writeValue(stringify, o);
objToONode = (ObjectNode) mapper.readTree(stringify.toString());
} catch (JsonMappingException e) {
Logger.error("ERROR MAPPING JSON from object!", e);
} catch (JsonGenerationException e) {
Logger.error("ERROR GENERATING JSON from object!", e);
} catch (IOException e) {
Logger.error("ERROR IO when writing JSON from object!", e);
}
Logger.debug("Object as ObjectNode : " + objToONode);
return objToONode;
}
Related
I am trying to trim the JSON key in order to avoid spaces in the JSON requests.
JSON Object would look like with white space, (check for "eq")
{
"page": 0,
"size": 25,
"and":{
"eq ": [
{
"field":"id",
"value": "60536"
}
]
}
}
I find lot of solution ranging from SimpleModule to JsonDeserializer but all generally work on the value part. How can I trim the key itself which then correctly converts into my Java POJO?
public class SearchInDTO implements InDTO {
private Integer pageNo;
private Integer pageSize;
private ANDFilter andFilter;
#JsonProperty("page")
public Integer getPageNo() {
return pageNo;
}
public void setPageNo(Integer pageNo) {
this.pageNo = pageNo;
}
#JsonProperty("size")
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
#JsonProperty("and")
public ANDFilter getAndFilter() {
return andFilter;
}
public void setAndFilter(ANDFilter andFilter) {
this.andFilter = andFilter;
}
public static class EQFilter extends FieldValue
{
#JsonProperty("field")
public String getFieldName() {
return super.getFieldName();
}
#JsonProperty("value")
public String getValue() {
return super.getValue();
}
#Override
public String toString() {
final StringBuilder sb = new StringBuilder("EQFilter{");
sb.append(super.toString());
sb.append('}');
return sb.toString();
}
}
public static class FieldValue
{
private String fieldName;
private String value;
#JsonProperty("field")
public String getFieldName() {
return fieldName;
}
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
#JsonProperty("value")
public String getValue() {
if(value == null) return value;
return value.toLowerCase();
}
public void setValue(String value) {
this.value = value;
}
}
public static class ANDFilter {
private List<EQFilter> eqFilters = new ArrayList<>();
#JsonProperty("eq")
public List<EQFilter> getEqFilters() {
return eqFilters;
}
public void setEqFilters(List<EQFilter> eqFilters) {
this.eqFilters = eqFilters;
}
}
}
Solution with custom JsonParser implementation:
public class MyJsonParser extends JsonParserDelegate {
public MyJsonParser(JsonParser parser) {
super(parser);
}
#Override
public String getCurrentName() throws IOException {
return super.getCurrentName().trim();
}
}
public class MyJsonParserFactory extends MappingJsonFactory {
#Override
protected JsonParser _createParser(InputStream in, IOContext ctxt) throws IOException {
return new MyJsonParser(super._createParser(in, ctxt));
}
#Override
protected JsonParser _createParser(Reader r, IOContext ctxt) throws IOException {
return new MyJsonParser(super._createParser(r, ctxt));
}
#Override
protected JsonParser _createParser(char[] data, int offset, int len, IOContext ctxt, boolean recyclable) throws IOException {
return new MyJsonParser(super._createParser(data, offset, len, ctxt, recyclable));
}
#Override
protected JsonParser _createParser(byte[] data, int offset, int len, IOContext ctxt) throws IOException {
return new MyJsonParser(super._createParser(data, offset, len, ctxt));
}
#Override
protected JsonParser _createParser(DataInput input, IOContext ctxt) throws IOException {
return new MyJsonParser(super._createParser(input, ctxt));
}
}
#Component
public class MyJackson2ObjectMapperBuilderCustomizer implements Jackson2ObjectMapperBuilderCustomizer {
#Override
public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
jacksonObjectMapperBuilder.factory(new MyJsonParserFactory());
}
}
I am struggling to parse the below json using jackson libraries
{"result":[{"userID":"xyz","firstName":"abc","lastName":"def","vFlag":"false","URL":"xyz://abc.com/cti.do?sysparm_caller=abc%20def&sysparm_caller_phone=+1 800 123 456"}]}
the square bracket after the "result" seems to be causing the issue.
I already have UNWRAP_ROOT_VALUE set in my code.
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
If i remove the [] then the json to pojo works fine. Is their any annotation i can use without fiddling around with string manipulations ?
POJO class
package com.parse.input;
import com.fasterxml.jackson.annotation.JsonRootName;
#JsonRootName(value = "result")
public class Employee {
private String userID = null;
private String firstName = null;
private String lastName = null;
private String vFlag = null;
private String uRl = null;
public String getUserID() {
return userID;
}
public void setUserID(String userID) {
this.userID = userID;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getVFlag() {
return vFlag;
}
public void setVFlag(String vipFlag) {
this.vFlag = vipFlag;
}
public String getURL() {
return uRl;
}
public void setURL(String ctiURL) {
this.uRl = ctiURL;
}
}
======And the Code to invoke REST API and parse the response======
Client restClient = Client.create();
WebResource webResource = restClient.resource(wURL);
ClientResponse resp = webResource.accept(MediaType.APPLICATION_JSON)
.header("Authorization", "Basic " + authStringEnc)
.header("EXT_URL", sURL + inputParameter)
.get(ClientResponse.class);
String output = resp.getEntity(String.class);
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
try {
System.out.println("Starting to parse the employee response");
Employee employee = mapper.readValue(ouput.toString(), Employee.class);
} catch (JsonParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JsonMappingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I was able to get around it like this.
try{
JSONObject j=new JSONObject(output.toString());
extractedJsonEmployee = j.getJSONArray("result").get(0).toString();
} catch (JSONException e) {
e.printStackTrace();
}
//Commented out the UNWRAP_ROOT_VALUE, since i am already taking out the root
Employee employee = mapper.readValue(extractedJsonEmployee, Employee.class);
I've make HttpsURLConnection to receive some information about my server.
The result of response is :
{"about":{"title":"NiFi","version":"1.1.0","uri":"https://localhost:443/api/","contentViewerUrl":"/nifi-content-viewer/","timezone":"CET"}}
How is possible to extract all attributes and key/value ?
About.class file
public class About {
private List<AboutObject> about;
public About()
{
// this.about = about;
}
public List<AboutObject> getAbout() {
return this.about;
}
public void setAbout(List<AboutObject> about) {
this.about = about;
}
}
AboutObject.class
public class AboutObject {
private String title;
private String uri;
private String contentViewerUrl;
private String timezone;
public String getTitle()
{
return this.title;
}
public void setTitle(String title)
{
this.title = title;
}
public String getUri()
{
return this.uri;
}
public void setUri(String uri)
{
this.uri = uri;
}
public String getContentViewerUrl()
{
return this.contentViewerUrl;
}
public void setContentViewerUrl(String contentViewerUrl)
{
this.contentViewerUrl = contentViewerUrl;
}
public String getTimeZone()
{
return this.timezone;
}
public void setTimeZone(String timezone)
{
this.timezone = timezone;
}
}
Main.class
HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
// optional default is GET
con.setRequestMethod("GET");
//add request header
con.setRequestProperty("User-Agent", USER_AGENT);
int responseCode = con.getResponseCode();
System.out.println("\nSending 'GET' request to URL : " + url);
System.out.println("Response Code : " + responseCode);
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
//print result
System.out.println(response.toString());
System.out.println("Contenu de in = " + in.toString());
ObjectMapper mapper = new ObjectMapper();
//Staff objStaff = new Staff();
System.out.println("Object to JSON in file");
mapper.writeValue(new File("output/file.json"), response);
System.out.println("Convert JSON string from file to Object");
//String about = mapper.readValue(new File("output/file.json"), String.class);
About about = mapper.readValue(new File("output/file.json"), About.class);
Error
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of About: no String-argument constructor/factory method to deserialize from String value ('{"about":{"title":"NiFi","version":"1.1.0","uri":"https://localhost:443/api/","contentViewerUrl":"/nifi-content-viewer/","timezone":"CET"}}') at [Source: output/file.json; line: 1, column: 1]
Thanks for you help
The test json you show doesn't have the array wrapper used in your About object. You're also missing the version field in your AboutObject and the timezone field uses the wrong case.
Your example worked when I updated your objects:
public class About {
private AboutObject about;
public AboutObject getAbout() {
return about;
}
public void setAbout(AboutObject about) {
this.about = about;
}
}
public class AboutObject {
private String title;
private String uri;
private String contentViewerUrl;
private String timezone;
private String version;
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
public String getUri() {
return this.uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public String getContentViewerUrl() {
return this.contentViewerUrl;
}
public void setContentViewerUrl(String contentViewerUrl) {
this.contentViewerUrl = contentViewerUrl;
}
public String getTimezone() {
return timezone;
}
public void setTimezone(String timezone) {
this.timezone = timezone;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
}
Test:
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
String obj = "{\"about\":{\"title\":\"NiFi\",\"version\":\"1.1.0\",\"uri\":\"https://localhost:443/api/\",\"contentViewerUrl\":\"/nifi-content-viewer/\",\"timezone\":\"CET\"}}";
About about = mapper.readValue(obj, About.class);
}
I have a json that looks like this:
[
{
_id: "54b8f62fa08c286b08449b8f",
loc: [
36.860983,
31.0567
]
},
{
_id: "54b8f6aea08c286b08449b93",
loc: {
coordinates: [ ]
}
}
]
As you can see, loc object is sometimes is a json object, sometimes is a double array. Without writing a custom deserializer, is there a way to avoid JsonSyntaxException and set the loc object to null when it is a json object rather than a double array.
There aren't any easy way (I mean a property/method call at Gson) for custom seralization/deserialization of a specific field at a json value.
You can see source code of com.google.gson.internal.bind.ReflectiveTypeAdapterFactory, and debug on its inner class Adapter's read method. (That's where your JsonSyntaxException occurs)
You can read Custom serialization for JUST specific fields and track its links. It may be implemented at future release of Gson. (Not available at latest release 2.2.4)
I would write some code for this. Maybe that's not what you are looking for but it may help somebody else.)
Solution 1 (This has less code compared with the second solution but second solution's performance is much more better):
public class SubClass extends BaseClass {
private double[] loc;
}
public class BaseClass {
#SerializedName("_id")
private String id;
}
public class CustomTypeAdapter extends TypeAdapter<BaseClass> {
private Gson gson;
public CustomTypeAdapter() {
this.gson = new Gson();
}
#Override
public void write(JsonWriter out, BaseClass value)
throws IOException {
throw new RuntimeException("Not implemented for this question!");
}
#Override
public BaseClass read(JsonReader in) throws IOException {
BaseClass instance;
try {
instance = gson.fromJson(in, SubClass.class);
} catch (Exception e) {
e.printStackTrace();
instance = gson.fromJson(in, BaseClass.class);
}
return instance;
}
}
Test:
private void test() {
String json = "[{_id:\"54b8f62fa08c286b08449b8f\",loc:[36.860983,31.0567]},{_id:\"54b8f6aea08c286b08449b93\",loc:{coordinates:[]}}]";
Type collectionType = new TypeToken<List<BaseClass>>(){}.getType();
Gson gson = new GsonBuilder().registerTypeAdapter(BaseClass.class, new CustomTypeAdapter()).create();
List<BaseClass> list = gson.fromJson(json, collectionType);
for(BaseClass item : list) {
if(item instanceof SubClass) {
System.out.println("item has loc value");
SubClass subClassInstance = (SubClass)item;
} else {
System.out.println("item has no loc value");
BaseClass baseClassInstance = item;
}
}
}
Solution 2 (It is one of the Gson Developers suggestion. See original post.):
Copy below class to your project. It is going to be a base class for your custom TypeAdapterFactorys.
public abstract class CustomizedTypeAdapterFactory<C>
implements TypeAdapterFactory {
private final Class<C> customizedClass;
public CustomizedTypeAdapterFactory(Class<C> customizedClass) {
this.customizedClass = customizedClass;
}
#SuppressWarnings("unchecked") // we use a runtime check to guarantee that 'C' and 'T' are equal
public final <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
return type.getRawType() == customizedClass
? (TypeAdapter<T>) customizeMyClassAdapter(gson, (TypeToken<C>) type)
: null;
}
private TypeAdapter<C> customizeMyClassAdapter(Gson gson, TypeToken<C> type) {
final TypeAdapter<C> delegate = gson.getDelegateAdapter(this, type);
final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
return new TypeAdapter<C>() {
#Override public void write(JsonWriter out, C value) throws IOException {
JsonElement tree = delegate.toJsonTree(value);
beforeWrite(value, tree);
elementAdapter.write(out, tree);
}
#Override public C read(JsonReader in) throws IOException {
JsonElement tree = elementAdapter.read(in);
afterRead(tree);
return delegate.fromJsonTree(tree);
}
};
}
/**
* Override this to muck with {#code toSerialize} before it is written to
* the outgoing JSON stream.
*/
protected void beforeWrite(C source, JsonElement toSerialize) {
}
/**
* Override this to muck with {#code deserialized} before it parsed into
* the application type.
*/
protected void afterRead(JsonElement deserialized) {
}
}
Write your POJO and your custom CustomizedTypeAdapterFactory. Override afterRead method and handle double array as you asked at your question:
public class MyClass {
#SerializedName("_id")
private String id;
private double[] loc;
// getters/setters
}
private class MyClassTypeAdapterFactory extends CustomizedTypeAdapterFactory<MyClass> {
private MyClassTypeAdapterFactory() {
super(MyClass.class);
}
#Override protected void afterRead(JsonElement deserialized) {
try {
JsonArray jsonArray = deserialized.getAsJsonObject().get("loc").getAsJsonArray();
System.out.println("loc is not a double array, its ignored!");
} catch (Exception e) {
deserialized.getAsJsonObject().remove("loc");
}
}
}
Test:
private void test() {
String json = "[{_id:\"54b8f62fa08c286b08449b8f\",loc:[36.860983,31.0567]},{_id:\"54b8f6aea08c286b08449b93\",loc:{coordinates:[]}}]";
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new MyClassTypeAdapterFactory())
.create();
Type collectionType = new TypeToken<List<MyClass>>(){}.getType();
List<MyClass> list = gson.fromJson(json, collectionType);
for(MyClass item : list) {
if(item.getLoc() != null) {
System.out.println("item has loc value");
} else {
System.out.println("item has no loc value");
}
}
}
This is how I did this. It is shorter, but I think #DevrimTuncers answer is the best one.
//This is just Double array to use as location object
public class Location extends ArrayList<Double> {
public Double getLatidute() {
if (this.size() > 0) {
return this.get(0);
} else {
return (double) 0;
}
}
public Double getLongitude() {
if (this.size() > 1) {
return this.get(1);
} else {
return (double) 0;
}
}
public static class LocationDeserializer implements JsonDeserializer<Location> {
#Override
public Location deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
try {
JsonArray array = json.getAsJsonArray();
Location location = new Location();
for (int i = 0; i < array.size(); i++) {
location.add(array.get(i).getAsDouble());
}
return location;
} catch (Exception e) {
return null;
}
}
}
}
I'm working with an api (Phillips Hue) that wraps all of it's json responses in an array with one entry (the content).
Example:
[{
"error": {
"type": 5,
"address": "/",
"description": "invalid/missing parameters in body"
}
}]
I usually write standard POJO's parsed by GSON to handle responses but since the response is not a json object I'm a bit stumped on the best way to deal with this. I didn't really want every object to actually be an array that I have to call .get(0) on.
Example of the POJO if it was a JSON obj and NOT wrapped in an array.
public class DeviceUserResponse {
private DeviceUser success;
private Error error;
public DeviceUser getSuccess() {
return success;
}
public Error getError() {
return error;
}
public static class Error {
private int type;
private String address;
private String description;
public int getType() {
return type;
}
public String getAddress() {
return address;
}
public String getDescription() {
return description;
}
#Override
public String toString() {
return "Type: " + this.type
+ " Address: " + this.address
+ " Description: " + this.description;
}
}
}
What I have to do right now:
ArrayList<DeviceUserResponse> response.get(0).getError();
Is there a way that I can strip this array for every response or am I just going to have to do a .get(0) in my POJO's and just not expose it?
I think you've to go with custom deserialization in order to "strip out" the array.
Here a possible solution.
An adapter for your response POJO:
public class DeviceUserResponseAdapter extends TypeAdapter<DeviceUserResponse> {
protected TypeAdapter<DeviceUserResponse> defaultAdapter;
public DeviceUserResponseAdapter(TypeAdapter<DeviceUserResponse> defaultAdapter) {
this.defaultAdapter = defaultAdapter;
}
#Override
public void write(JsonWriter out, DeviceUserResponse value) throws IOException {
defaultAdapter.write(out, value);
}
#Override
public DeviceUserResponse read(JsonReader in) throws IOException {
in.beginArray();
assert(in.hasNext());
DeviceUserResponse response = defaultAdapter.read(in);
in.endArray();
return response;
}
}
A factory for your adapter:
public class DeviceUserResponseAdapterFactory implements TypeAdapterFactory {
#Override
#SuppressWarnings("unchecked")
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
if (type.getRawType()!=DeviceUserResponse.class) return null;
TypeAdapter<DeviceUserResponse> defaultAdapter = (TypeAdapter<DeviceUserResponse>) gson.getDelegateAdapter(this, type);
return (TypeAdapter<T>) new DeviceUserResponseAdapter(defaultAdapter);
}
}
Then you've to register and user it:
DeviceUserResponseAdapterFactory adapterFactory = new DeviceUserResponseAdapterFactory();
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.registerTypeAdapterFactory(adapterFactory).create();
DeviceUserResponse response = gson.fromJson(json, DeviceUserResponse.class);
System.out.println(response.getError());
This solution will not work if you have the DeviceUserResponse inside other complex JSON object. I that case the adapter will try to find an array and will terminate with an error.
Another solution is to parse it as array and then in your "communication" layer you get only the first element. This will preserve the GSon deserialization.
In the comment you're asking for a more generic solution, here one:
The adapter:
public class ResponseAdapter<T> extends TypeAdapter<T> {
protected TypeAdapter<T> defaultAdapter;
public ResponseAdapter(TypeAdapter<T> defaultAdapter) {
this.defaultAdapter = defaultAdapter;
}
#Override
public void write(JsonWriter out, T value) throws IOException {
defaultAdapter.write(out, value);
}
#Override
public T read(JsonReader in) throws IOException {
in.beginArray();
assert(in.hasNext());
T response = defaultAdapter.read(in);
in.endArray();
return response;
}
}
The factory:
public class ResponseAdapterFactory implements TypeAdapterFactory {
#Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
if ((type.getRawType().getSuperclass() != Response.class)) return null;
TypeAdapter<T> defaultAdapter = (TypeAdapter<T>) gson.getDelegateAdapter(this, type);
return (TypeAdapter<T>) new ResponseAdapter<T>(defaultAdapter);
}
}
Where Response.class is your super class from which all the service responses inherit.
The first solution advices are still valid.